В последней версии awk есть опция inplace
которая может использоваться для выполнения операций, аналогичных опции sed
-i. Однако я не могу заставить его работать с оператором print
. Давайте посмотрим на мой пример. Содержимое тестового файла:
11 aa 22 bb
root@localhost:~# cat test 11 aa 22 bb
Если я не использую -i inplace
, я могу получить желаемый результат в консоли.
root@localhost:~# awk 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' test begin 111aa 22 bb end
Когда я добавляю -i inplace
, это то, что я получил.
root@localhost:~# awk -i inplace 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' test begin end root@localhost:~# cat test 111aa 22 bb root@localhost:~#
Как улучшить код и получить то, что я хочу?
Моя версия awk – 4.1.1
.
root@localhost:~# awk --version GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2-p3, GNU MP 6.0.0) Copyright (C) 1989, 1991-2014 Free Software Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. root@localhost:~#
root@localhost:~# awk --version GNU Awk 4.1.2, API: 1.1 Copyright (C) 1989, 1991-2015 Free Software Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. root@localhost:~# cat file 11 aa 22 bb root@localhost:~# awk 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' file begin 111aa 22 bb end root@localhost:~# awk -i inplace 'BEGIN{print "begin"} $1=="11"{print "111" $2; next} 1; END{print "end"}' file begin end root@localhost:~# cat file 111aa 22 bb root@localhost:~#
Я думаю, вам нужно использовать BEGINFILE вместо BEGIN и ENDFILE вместо END для начала и конца для печати в файл.
По крайней мере, это работает на cygwin.
Rob@Rob-PC /cygdrive/c/tmp $ awk --version GNU Awk 4.1.1, API: 1.1 (GNU MPFR 3.1.2, GNU MP 6.0.0) Copyright (C) 1989, 1991-2014 Free Software Foundation. Rob@Rob-PC /cygdrive/c/tmp $ echo "11 aa 22 bb" > test Rob@Rob-PC /cygdrive/c/tmp $ awk -i inplace 'BEGINFILE{print "begin"} $1=="11"{print "111" $2; next} 1; ENDFILE{print "end" >> "test"}' test Rob@Rob-PC /cygdrive/c/tmp $ cat test begin 111aa 22 bb end
Петли BEGIN
и END
запускаются до того, как файл будет обработан и после его обработки полностью. -i inplace
имеет смысл только при обработке файла. Я не могу быть уверен, не проверяя исходный код, но поэтому представляется разумным, что BEGIN
и END
здесь не работают.
Как уже было предложено, для этого и существуют BEGINFILE
и ENDFILE
. Если они не работают в вашей настройке, вам придется использовать обходные пути. Хотя совпадение первой строки легко ( if(NR==1){print "begin"}
), то сопоставление последней строки немного сложнее. Некоторые трюки, которые вы можете использовать:
Добавьте начальную и конечную строки, используя другой инструмент:
perl -i -007ne 'print "begin\n${_}end\n"' file && awk -i inplace '$1=="11"{print "111" $2; next}1;' file
или
printf "begin\n%s\nend" "$(cat file)"
Используйте awk
для «begin» и добавьте «end» позже:
awk -i inplace 'NR==1{print "begin"}$1=="11"{print "111" $2; next}1;' file && echo "end" >> file
Делайте все это с помощью инструмента, который может понять eof
. Переключатель -a
Perl заставляет его действовать как awk
: он будет разделять поля на пробелы на @F
. Просто как awk
, переключатель -F
позволяет установить разделитель полей. Переключатель -i
редактирует файл на месте:
perl -i -lane '$.==1 && print "begin"; eof && print "end"; if($F[0]=="11"){print "111$F[0] $F[1]"; next} print;' file