Змініть ширину першого стовпця у файлі зі змінною кількістю полів, використовуючи awk


10

Я розумію, як використовувати функцію printf awk, але не хочу вказувати кожне поле.

Наприклад, припустимо, що це мій файл:

c1|c2|c3|c4|c5
c6|c7|c8|c9|c10
c11|c12|c13|c14|c15

Я хочу відформатувати його так, щоб першим полем кожного запису була ширина c11 - найдовша комірка в першому полі:

c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

Я розумію, що міг би вказати:

awk -F"|" '{printf "%-3s%s%s%s%s\n", $1, $2, $3, $4, $5}' file > newfile

Припустимо, я знаю, якою я хочу бути шириною першого стовпця, але я НЕ знаю, скільки полів у файлі. В основному я хочу зробити щось на кшталт:

... '{printf "%-3s|", $1}'

... а потім надрукуйте решту полів у оригінальному форматі.


Ще один спосіб вирішити це: sed 's/|/'' '' '' |/;s/\(...\) */\1/'(сюди додаються додаткові цитати, щоб вставити ці 3 пробіли, коли коментарі SE
видаляють

Відповіді:


14

Ви можете використовувати лише sprintfдля переформатування $1.

Вих.

$ awk 'BEGIN{OFS=FS="|"} {$1 = sprintf("%-3s",$1)} 1' file
c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

Лаконічні, ви також можете використовувати динамічне форматування і зі awk -vf1=3 'BEGIN{OFS=FS="|"}{$1=sprintf("%-*s",f1,$1)}1' test.txt
спринтом

@ A.Danischewski - Ну, даг. Я займався великим програмою awk протягом ~ 17 років, і ніколи раніше не стикався з цим. Подумати про всі клопоти, це врятувало б мене.
Пол Сінклер

6

Щоб визначити найбільшу / найдовшу довжину першого поля, а потім переформатувати значення в полі відповідно до цієї довжини, вам доведеться зробити два окремих проходи над файлом.

awk 'BEGIN     { OFS = FS = "|" }
     FNR == NR { if (m < (n=length($1))) m = n; next }
               { $1 = sprintf("%-*s", m, $1); print }' file file

(зауважте, що вхідний файл вказаний двічі в командному рядку)

Для даних, які ви представляєте, це може отримати

c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

Перший прохід обробляється FNR == NRблоком, який просто відстежує найдовше поле, яке ви бачили досі ( mмістить максимальну видиму довжину), і переходить до наступного рядка.

Другий прохід обробляється останнім блоком, який переформатує перше поле за допомогою sprintf(). Рядок формату %-*sозначає "лівовиправдану рядок, ширина якої задається цілим аргументом перед аргументом, який містить фактичний рядок".

Очевидно, це можна розширити, щоб зробити всі стовпці, перетворивши скаляр mу масив, який містить максимальну ширину кожного стовпця:

$ awk 'BEGIN     { OFS = FS = "|" }
       FNR == NR { for (i=1; i<=NF; ++i) if (m[i] < (n=length($i))) m[i] = n; next }
                 { for (i=1; i<=NF; ++i) $i = sprintf("%-*s", m[i], $i); print }' file file
c1 |c2 |c3 |c4 |c5
c6 |c7 |c8 |c9 |c10
c11|c12|c13|c14|c15

1

Розумний спосіб - це те, що запропонував Steeldriver . Потрібний складний спосіб полягає в перегляді кожного поля:

$ awk -F'|' '{printf "%-3s|",$1; for(i=2;i<NF;i++){printf "%s|",$i} printf "%s\n", $i}' file
c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

Але просто sprintf $1і роби з цим.


1
Ви отримали це трохи назад, невеликі стислі висловлювання, як правило, більш складні. Ітерація над полями менш заплутана.
А.Данішевський

1

У Awk ви можете використовувати "*" для створення динамічного рядка формату printf.

Якщо ви вже знаєте довжину, ви можете передати довжину поля для першого стовпця за допомогою -v.

awk -vcol1=3 'BEGIN{FS="|"}{for(i=1;i<=NF;i++){if(i==1)printf "%*-s%s",col1,$i,FS;else if(i!=NF)printf "%s%s",$i,FS;else printf "%s\n",$i;};}' test.txt

Примітка: якщо ви не знали, яка довжина першого стовпця, ви можете зберігати значення в масиві, а потім знаходити максимальну довжину стовпчика по дорозі і роздруковувати все це в блоці END.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.