Печать запятой за исключением последней строки в Awk
у меня есть следующий скрипт
awk '{printf "%s", "-"", "}' $a >> positions;
здесь $a
сохраняет имя файла. На самом деле я записываю несколько значений столбцов в одну строку. Однако я хотел бы напечатать запятую, только если я не на последней строке.
6 ответов
Я бы сделал это, найдя количество строк перед запуском скрипта, например, с coreutils и bash:
awk -v nlines=$(wc -l < $a) '{printf "%s", "-"} NR != nlines { printf ", " }' $a >>positions
если ваш файл имеет только 2 столбца, также работает следующая альтернатива coreutils. Пример:
paste <(seq 5) <(seq 5 -1 1) | tee testfile
выход:
1 5
2 4
3 3
4 2
5 1
теперь замена вкладок на новые строки,paste
легко собирает дату в нужный формат:
<testfile tr '\t' '\n' | paste -sd-,
выход:
1-5,2-4,3-3,4-2,5-1
однопроходный подход:
cat "$a" | # look, I can use this in a pipeline!
awk 'NR > 1 { printf(", ") } { printf("%s-%s", , ) }'
обратите внимание, что я также упростил форматирование строки.
кроме этого:
awk '{printf t "-"} {t=", "}' $a >> positions
Да, выглядит немного сложно на первый взгляд. Поэтому я объясню, прежде всего давайте изменим printf
на print
для ясности:
awk '{print t "-"} {t=", "}' file
и посмотрите, что он делает, например, для файла с помощью этого простого содержания:
1 A
2 B
3 C
4 D
так он будет производить следующее:
1-A
, 2-B
, 3-C
, 4-D
трюк является предыдущим t
переменная, которая пуста в начале. Переменная будет установлена {t=...}
только на следующий шаг обработки после того, как он был показан {print t ...}
. Так что если мы (awk
) продолжить итерацию мы получим желаемую последовательность.
вот лучший способ, не прибегая к coreutils:
awk 'FNR==NR { c++; next } { ORS = (FNR==c ? "\n" : ", "); print , }' OFS="-" file file
вы можете подумать, что ОРС и ОФС awk были бы разумным способом справиться с этим:
$ awk '{print ,}' OFS="-" ORS=", " input.txt
но это приводит к окончательному ORS, потому что вход содержит новую строку в последней строке. Новая строка является разделителем записей, поэтому с точки зрения awk на входе есть пустая последняя запись. Вы можете обойти это с небольшим количеством хакерства,но результирующая сложность исключает элегантность однострочного.
Итак, вот мой взгляд на это. С тех пор, как ты сказал, что "запись нескольких значений столбцов", возможно, что mucking с ORS и OFS вызовет проблемы. Таким образом, мы можем достичь желаемого результата полностью с помощью форматирования.
$ cat input.txt
3 2
5 4
1 8
$ awk '{printf "%s%d-%d",t,,; t=", "} END{print ""}' input.txt
3-2, 5-4, 1-8
Это похоже на однопроходные подходы Майкла и рука, но он использует один printf
и правильно использует строку форматирования для форматирования.
Это, вероятно, будет работать незначительно лучше, чем решение Майкла, потому что назначение должно занять меньше процессора, чем тест, и заметно лучше чем любое из многопроходных решений, потому что файл должен быть прочитан только один раз.