2016-07-09 4 views
1

Я в процессе перехода от zsh к bash, и мне нужно создать скрипт bash, который может удалить повторяющиеся записи в $PATH без переупорядочения записей (таким образом, нет sort -d magic). В zsh есть несколько ярких ярлыков для обработки массивов, которые упрощали это, но я не знаю о таких ярлыках в bash. Я наткнулся на this answer, который получил мне 90% пути, но есть небольшая проблема, которую я хотел бы лучше понять. Похоже, что когда я запускаю эту команду awk, последняя обработанная запись неправильно соответствует шаблону.Awk pattern всегда соответствует последней записи?

$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:cc 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb" 
aa:bb:cc:bb 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:" # note trailing colon 
aa:bb:cc: 

Я не понимаю, AWK достаточно хорошо, чтобы знать, почему он ведет себя таким образом, но я сумел обойти эту проблему, используя промежуточный массив, как так.

array=($(awk 'BEGIN{RS=":";ORS=" "}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:")) 
# Use a subshell to avoid modifying $IFS in current context 
echo $(export IFS=":"; echo "${array[*]}") 
aa:bb:cc 

Это кажется неоптимальным решением, однако, поэтому мой вопрос: я сделал что-то неправильное в команде AWK, что является причиной ложных положительных матчей на финальную записи обрабатывается?

ответ

4

Последняя запись в вашей исходной строке - cc\n, которая отличается от cc. Когда не зная, что происходит в любой программе на любом языке, добавив некоторые операторы печати является шаг 1 для отладки/исследования:

$ awk 'BEGIN{RS=ORS=":"} {print "<"$0">"}' <<<"aa:bb:cc:aa:bb:cc" 
<aa>:<bb>:<cc>:<aa>:<bb>:<cc 
>:$ 

Если вы хотите RS быть : или \n то просто заявить, что (с GNU AWK по крайней мере,):

$ awk 'BEGIN{RS="[:\n]"; ORS=":"} !a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:$ 

$ во всех выше моя подсказка.

+0

Хороший пример, чтобы увидеть, что происходит. Но не могли бы вы объяснить, почему в строку добавлена ​​новая строка? –

+2

Это то, что делает bash, по сути делает 'cmd <<<" string "' ведет себя так же, как 'echo" string "| cmd', но без дополнительной команды ('echo') и трубы. Инструменты обработки текста POSIX (sed, awk, grep и т. Д.) Гарантируют, что они будут работать только с текстовыми файлами POSIX, иначе вы получите неопределенное поведение, поэтому, если файл или входной поток не заканчивается новой строкой, то это не текстовый файл POSIX/stream, так что конечная новая строка необходима для обеспечения ожидаемого/желаемого поведения. –

+1

Спасибо! Теперь я лучше понимаю, почему возникает проблема, которая приближает меня к правильному решению проблемы. Как небольшая проблема, как это могло быть, ваш ответ был очень полезен для меня. – Christopher

0

Другой возможный обходной путь вместо того, чтобы ваш Баш решение массив

$ echo "aa:bb:cc:aa:bb:cc" | tr ':' '\n' | awk '!a[$0]++' | paste -sd: 
aa:bb:cc 

 Смежные вопросы

  • Нет связанных вопросов^_^