Как сохранить исходные пробелы между полями в awk?
При обработке ввода с помощью awk
иногда я хочу редактировать одно из полей, не касаясь чего-либо еще. Рассмотрим это:
$ ls -l | awk 1
total 88
-rw-r--r-- 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack 4306 Dec 29 09:16 test1.html
-rw-r--r-- 1 jack jack 5476 Dec 7 08:09 test1.js
Если я не редактирую ни одно из полей ($1
, $2
,...), все сохраняется как есть. Но если я скажу, что хочу сохранить только первые 3 символа первого поля:
$ ls -l | awk '{$1 = substr($1, 1, 3) } 1'
tot 88
-rw 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css
-rw 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js
-rw 1 jack jack 4306 Dec 29 09:16 test1.html
-rw 1 jack jack 5476 Dec 7 08:09 test1.js
Исходное пробел между всеми полями заменяется простым пространством.
Есть ли способ сохранить исходные пробелы между полями?
UPDATE
В этом примере относительно легко редактировать первые 4 поля. Но что, если я хочу сохранить только 1-ю букву $5
, чтобы получить этот вывод:
-rw-r--r-- 1 jack jack 8 J 19 2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 J 19 2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack 4306 D 29 09:16 test1.html
-rw-r--r-- 1 jack jack 5476 D 7 08:09 test1.js
Ответы
Ответ 1
Я знаю, что это старый вопрос, но я думал, что должно быть что-то лучше. Этот ответ для тех, кто наткнулся на этот вопрос во время поиска. Если посмотреть в Интернете, я должен сказать, что @Håkon Hægland имеет лучший ответ, и именно это я использовал вначале.
Но вот мое решение. Используйте FPAT. Он может установить регулярное выражение, чтобы сказать, какое должно быть поле.
FPAT = "([[:space:]]*[[:alnum:][:punct:][:digit:]]+)";
В этом случае я говорю, что поле должно начинаться с нуля или более пустых символов и заканчивается в основном любым другим символом, кроме пустых символов. Здесь - ссылка, если у вас возникли проблемы с пониманием выражений POSIX
.
Кроме того, измените поле вывода на OFS = "";
separator, потому что, как только линия была обработана, на выходе будет добавлено дополнительное пустое пространство в качестве разделителя, если вы не измените OFS по умолчанию.
Я использовал тот же пример для тестирования.
$ cat example-output.txt
-rw-r--r-- 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack 4306 Dec 29 09:16 test1.html
-rw-r--r-- 1 jack jack 5476 Dec 7 08:09 test1.js
$ awk 'BEGIN { FPAT = "([[:space:]]*[[:alnum:][:punct:][:digit:]]+)"; OFS = ""; } { $6 = substr( $6, 1, 2); print $0; }' example-output.txt
-rw-r--r-- 1 jack jack 8 J 19 2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 J 19 2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack 4306 D 29 09:16 test1.html
-rw-r--r-- 1 jack jack 5476 D 7 08:09 test1.js
Имейте в виду. Теперь поля имеют ведущие пробелы. Поэтому, если поле нужно заменить чем-то другим, вы можете сделать
len = length($1);
$1 = sprintf("%"(len)"s", "-42-");
$ awk 'BEGIN { FPAT = "([[:space:]]*[[:alnum:][:punct:][:digit:]]+)"; OFS = ""; } { if(NR==1){ len = length($1); $1 = sprintf("%"(len)"s", "-42-"); } print $0; }' example-output.txt
-42- 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack 4306 Dec 29 09:16 test1.html
-rw-r--r-- 1 jack jack 5476 Dec 7 08:09 test1.js
Ответ 2
Если вы хотите сохранить пробел, вы также можете попробовать функцию split
.
В Gnu Awk версии 4 функция split
принимает 4 аргумента, где последние являются разделителями между полями. Например,
echo "a 2 4 6" | gawk ' {
n=split($0,a," ",b)
a[3]=7
line=b[0]
for (i=1;i<=n; i++)
line=(line a[i] b[i])
print line
}'
выводит вывод
a 2 7 6
Ответ 3
Можно сохранить исходные пробелы, отредактировав $0
вместо отдельных полей ($1
, $2
,...), например:
$ ls -l | awk '{$0 = substr($1, 1, 3) substr($0, length($1) + 1)} 1'
tot 88
-rw 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css
-rw 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js
-rw 1 jack jack 4306 Dec 29 09:16 test1.html
-rw 1 jack jack 5476 Dec 7 08:09 test1.js
Это довольно легко сделать при редактировании первого столбца, но при редактировании других проблем возникает проблема ($2
,..., $4
) и ломается после полей, где ширина пробела между ними не является ($5
и выше в этом примере).
UPDATE
На основе @Håkon Hægland ответьте здесь, чтобы сохранить первые 2 символа 6-го поля (месяца):
{
n = split($0, f, " ", sep)
f[6] = substr(f[6], 1, 2)
line = sep[0]
for (i = 1; i <= n; ++i) line = line f[i] sep[i]
print line
}