2013-10-06 4 views
2

Хорошо, так что я не знаю, как я мог использовать sed или awk, чтобы извлечь блок текста между двумя пустыми строками, а также опустить часть извлеченного текста. Ответы, которые я получил, в значительной степени удовлетворили мои потребности, но теперь я делаю что-то дополнительное для удовольствия (и для OCD).Условный Сортировка с использованием Awk или сортировки

Я хочу сортировать выходные данные из awk в этом раунде. Я нашел this question & answer, но это не совсем помогает мне решить проблему. Я также попытался обернуть голову вокруг большого количества документации awk, чтобы попытаться выяснить, как я могу это сделать, но безрезультатно.

Так вот блок кода в моем скрипте, который делает всю грязную работу:

# This block of stuff fetches the nameservers as reported by the registrar and DNS zone 
# Then it gets piped into awk to work some more formatting magic... 
# The following is a step-for-step description since I can't put comments inside the awk block: 
# BEGIN: 
#  Set the record separator to a blank line 
#  Set the input/output field separators to newlines 
# FNR == 3: 
#  The third block of dig's output is the nameservers reported by the registrar 
#  Also blanks the last field & strips it since it's just a useless dig comment 
dig +trace +additional $host | \ 
awk -v host="$host" ' 
    BEGIN { 
     RS = ""; 
     FS = "\n" 
    } 
    FNR == 3 { 
     print "Nameservers of",host,"reported by the registrar:"; 
     OFS = "\n"; 
     $NF = ""; sub(/[[:space:]]+$/, ""); 
     print 
    } 
' 

А вот выход, если я прохожу google.com в качестве значения $host (других имен хостов может производить выход отличающегося линии отсчеты):

Nameservers of google.com reported by the registrar: 
google.com.   172800 IN NS ns2.google.com. 
google.com.   172800 IN NS ns1.google.com. 
google.com.   172800 IN NS ns3.google.com. 
google.com.   172800 IN NS ns4.google.com. 
ns2.google.com.   172800 IN A 216.239.34.10 
ns1.google.com.   172800 IN A 216.239.32.10 
ns3.google.com.   172800 IN A 216.239.36.10 
ns4.google.com.   172800 IN A 216.239.38.10 

идея заключается в том, либо с помощью существующего блока AWK или выхода конвейера AWK в в комбинацию большего AWK, сортировать, или что-то еще, вроде тех, что блок текста, используя условный алгоритм:

if (column 4 == 'NS') 
    sort by column 5 
else // This will ensure that the col 1 sort includes A and AAAA records 
    sort by column 1 

Я очень много получил те же предпочтения ответов как на предыдущий вопрос:

  1. Самое главное, она должна быть портативной, так как я столкнулся с различным поведением между OS X (мой домашняя система) и Fedora (то, что я использую на работе) при использовании sed (пришлось заменить его gsed на OS X) и флагом grep -m (используется в другом скрипте)
  2. Объяснение того, как работает решение, будет очень высоко ценится, как возможность обучения более, чем что-либо другое. Я уже многому научился от решения awk, уже представленного в предыдущем вопросе.
  3. Если решение может быть осуществлено в пределах одного блока AWK, что также будет удивительным
  4. Если нет, то что-то простое и красноречивым, что я могу выход трубы AWK через будет достаточно
+0

Традиционное решение трубопровода можно было бы добавить, как вы намекнули, еще один шаг, который добавляет дополнительный «тип = 1 (или =) столбец 2 типа и конец каждая строка, и в то же время переформатирует все типы записей в общий формат, который будет работать с 'sort', (самым простым способом, вероятно, дублируя столбцы в начале строки). Последним шагом в конвейере, выходящим из 'sort', было бы восстановление исходного формата каждой строки на основе столбца типа. Удачи. – shellter

+1

В обоих случаях вы можете сортировать по '1,5', учитывая, что поле 1 является константой для' type == 'NS'' – wildplasser

ответ

1

Вот решение основанный на идее @ shellter. Направьте вывод из ваших серверов имен записей в этом:

awk '$4 == "NS" {print $1, $5, $0} $4 == "A" {print $1, $1, $0}' | sort | cut -f3- -d' ' 

Объяснение:

  • С awk, мы принимаем только NS и A записи, и повторно печатать ту же строку с префиксом: первичный поиск столбца + вторичный столбец поиска
  • sort будет сортировать линии, благодаря тому, как мы установили первую и вторую колонку, заказ должен быть как вы хотели
  • С cut мы избавимся от префикса, который мы использовали для сортировки
+0

Мне пришлось немного изменить код, чтобы поставить первый оператор печати вне awk в отдельном эхом чтобы сделать эту работу, но она в значительной степени работала прямо из коробки. Я тестирую это на работе прямо сейчас, поэтому мне придется изучить его, чтобы узнать, как все это работает во время моего перерыва и настроить его по мере необходимости, чтобы сделать его совместимым с IPv6. Благодаря! –

+0

Теперь, когда у меня была возможность работать над этим, есть одна небольшая ошибка в этом, что я смог решить: имена хостов, которые появляются после серверов имен в алфавитном порядке, вызывают сортировку групп NS & A. После разреза я пробрался через sort -rk 4, и это исправить. :) –

0

Я знаю, что вы спросили о awk решение, но так как вы помечать его с bash тоже я думал, что обеспечить такую ​​версию.Он также должен быть более компактен, чем awk;)

# the whole line 
declare -a lines 
# the key to use for sorting 
declare -a keys 

# insert into the arrays at the appropriate position 
function insert 
{ 
    local key="$1" 
    local line="$2" 
    local count=${#lines[*]} 
    local i 
    # go from the end backwards 
    for((i=count; i>0; i-=1)) 
    do 
     # if we have the insertion point, break 
     [[ "${keys[i-1]}" > "$key" ]] || break 
     # shift the current item to make room for the new one 
     lines[i]=${lines[i-1]} 
     keys[i]=${keys[i-1]} 
    done 
    # insert the new item 
    lines[i]=$line 
    keys[i]=$key 
} 

# This block of stuff fetches the nameservers as reported by the registrar and DNS zone 
#  The third block of dig's output is the nameservers reported by the registrar 
#  Also blanks the last field & strips it since it's just a useless dig comment 
block=0 
dig +trace +additional $host | 
while read f1 f2 f3 f4 f5 
do 
    # empty line begins new block 
    if [ -z "$f1" ] 
    then 
     # increment block counter 
     block=$((block+1)) 
     # and read next line 
     continue 
    fi 

    # if we are not in block #3, read next line 
    [[ $block == 3 ]] || continue 

    # ;; ends the block 
    if [[ "$f1" == ";;" ]] 
    then 
     echo "Nameservers of $host reported by the registrar:" 
     # print the lines collected so far 
     for((i=0; i<${#lines[*]}; i+=1)) 
     do 
      echo ${lines[i]} 
     done 
     # don't bother reading the rest 
     break 
    fi 

    # figure out what key to use for sorting 
    if [[ "$f4" == "NS" ]] 
    then 
     key=$f5 
    else 
     key=$f1 
    fi 
    # add the line to the arrays 
    insert "$key" "$f1 $f2 $f3 $f4 $f5" 
done 
Смежные вопросы