Печать запятой за исключением последней строки в 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 и правильно использует строку форматирования для форматирования.

Это, вероятно, будет работать незначительно лучше, чем решение Майкла, потому что назначение должно занять меньше процессора, чем тест, и заметно лучше чем любое из многопроходных решений, потому что файл должен быть прочитан только один раз.


awk '{a[NR]="-";next}END{for(i=1;i<NR;i++){print a[i]", " }}' $a > positions