Это не имеет никакого смысла. Просто замените его, когда вы найдете его:
awk -v nText="$2" '/text/{$0="new text " nText} 1' test.xml
ASIDE: WRT использование ENVIRON, как описано ниже, считают это:
$ foo='a\tb'
$ printf '%s\n' "$foo"
a\tb
$ awk -v foo="$foo" 'BEGIN{ print foo }'
a b
$ foo="$foo" awk 'BEGIN{ print ENVIRON["foo"] }'
a\tb
Итак, ЭНВАЙРОН лучше, если вы не хотите escape-последовательность расширена, но для этого требуется больше кода, и она менее эффективна, если вам нужно значение foo
несколько раз, например в цикле (в этом случае вы бы использовали еще больше кода и больше дублирования слова foo
: foo="$foo" awk 'BEGIN{ foo=ENVIRON["foo"]; print foo }'
.)
Теперь давайте попробуем, когда интересующее вас значение хранится в позиционном параметре вместо переменная оболочки. Следуя схеме, мы, кажется, показывает выше, что было бы:
$ set -- 'a\tb'
$ printf '%s\n' "$1"
a\tb
$ awk -v foo="$1" 'BEGIN{ print foo }'
a b
$ 1="$1" awk 'BEGIN{ print ENVIRON["1"] }'
-bash: 1=a\tb: command not found
Конечно, это не работает, и тонкая вещь, которую вы должны быть осведомлены о том, что имя переменной оболочки для задания оболочки что происходит перед Teh вызова AWK не всегда может быть именем переменной оболочки вы хотите, чтобы получить значение, как это не может даже быть переменной можно присвоить:
$ foo="$1" awk 'BEGIN{ print ENVIRON["foo"] }'
a\tb
альтернативы, которая работает в все случаи должны указывать значение переменной в списке аргументов:
$ awk 'BEGIN{ foo=ARGV[1]; ARGV[1]=""; print foo }' "$1"
a\tb
, но это также имеет оговорки, так как вы можете больше не просто прокручивать ARGV, чтобы получить имена ваших входных файлов.
Теперь давайте сравним самые реалистичные возможности эволюции 2 сценариев, один с помощью -v
и один ENVIRON
:
$ awk -v var=100000000 'BEGIN{ print var }'
100000000
$ var=100000000 awk 'BEGIN{ print ENVIRON["var"] }'
100000000
Теперь предположим, что мы хотим использовать var
в качестве конечного значения для цикла.Вот 3-ий пример:
$ time awk -v var=100000000 'BEGIN{ for (i=1;i<=var;i++) i }'
real 0m7.813s
user 0m7.706s
sys 0m0.031s
$ time var=100000000 awk 'BEGIN{ for (i=1;i<=ENVIRON["var"];i++) i }'
real 0m11.673s
user 0m11.637s
sys 0m0.031s
Обратите внимание, насколько менее эффективна версия ENVIRON.
С другой стороны, что делать, если вам нужно просто использовать его пару раз в скрипте:
$ awk -v var=100000000 'BEGIN{ print var; if (var > 5) var = 5; print var }'
100000000
5
$ var=100000000 awk 'BEGIN{ print ENVIRON["var"]; if (ENVIRON["var"] > 5) ENVIRON["var"] = 5; print ENVIRON["var"] }'
100000000
5
Обратите внимание, насколько менее лаконичный код для версии ENVIRON есть.
В обоих вышеуказанных случаях, то вы не действительно хотите использовать ENVIRON [ «переменной»], кроме как инициализировать переменную AWK, а затем использовать это в остальной части кода:
$ time var=100000000 awk 'BEGIN{ var=ENVIRON["var"]; for (i=1;i<=var;i++) i }'
real 0m7.692s
user 0m7.612s
sys 0m0.031s
$ var=100000000 awk 'BEGIN{ var=ENVIRON["var"]; print var; if (var > 5) var = 5; print var }'
100000000
5
поэтому если вы не хотите, чтобы переписать код, как он развивается, если вы собираетесь использовать ENVIRON то эквивалент:
awk -v var=val 'BEGIN{ print var }'
не
var=val awk 'BEGIN{ print ENVIRON["var"] }'
, но вместо этого:
var=val awk 'BEGIN{ var=ENVIRON["var"]; print var }'
, который является длительным и повторы в лучшем случае по сравнению с использованием -v
.
что-то еще, чтобы рассмотреть, что, когда вы разборе файла и каждая запись отделена символом новой строки (предположим, что это не по умолчанию) вы хотите написать:
awk -v RS='\n' '1'
или
awk -v RS="$'\n'" '1'
установить RS на новую строку? Первая из них является, конечно же, гораздо более удобным и интуитивно понятно, и вы, конечно, не хотите, чтобы написать:
RS="$'\n'" awk 'BEGIN{ RS=ENVIRON["RS"] } 1'
насчет FS быть вкладка:
awk -v FS='\t' '{print NF}'
против
FS="$'\t'" awk 'BEGIN{ FS=ENVIRON["FS"] } {print NF}'
Точка - расширение экранов почти всегда является желательным эффектом, поэтому запись более длинного, более медленного и громоздкого кода, который отключает этот эффект, не будет хорошим по умолчанию способом написания вашей совместной де.
IMHO - просто используйте -v
, если вы не хотите, чтобы escape-последовательности были расширены и не хотели их избегать в назначении (чаще всего, когда значение, которое вы назначаете, хранится в переменной оболочки, как в приведенном выше примере):
$ awk -v foo='a\tb' 'BEGIN{ print foo }'
a b
$ awk -v foo='a\\tb' 'BEGIN{ print foo }'
a\tb
Final мысль - я постоянно говорю людям при написании циклов оболочки для использования по умолчанию:
while IFS= read -r var
do
whatever
done
в частности, я имею в виду использовать read -r var
по умолчанию, чтобы остановить побег расширяется в shell var iable, хотя в awk я говорю, используя awk -v var=
, чтобы вызвать расширение esk в переменной awk.
Причина очевидной несогласованности заключается в том, что оболочка - это инструмент для управления файлами и процессами и последовательные вызовы другим инструментам, в то время как awk - это инструмент для управления текстом.
Если вы назначаете переменную оболочки в цикле, например, она должна быть петлей на имена файлов, поэтому критически важно не расширять экраны, или результирующая переменная НЕ будет содержать имя файла, как предполагалось.
Если присвоить переменную AWK, то у него есть что-то делать с манипулирует текстом и наиболее распространенным является то, что текст содержит буквенные символы табуляции, новой строки и т.д. НЕ, что текст содержит буквенные \t
с и \n
сек Итак, AWK расширяется FS='\t'
до FS=<a literal tab>
, который является поведением, которое вы хотите для разбора файла с разделителями табуляции.
Поэтому, если у вас нет конкретной причины - не пишите инициализирующий код переменной оболочки, чтобы развернуть escapes, потому что это, вероятно, не то, что вам нужно, для какой оболочки используется, и писать код инициализации awk для расширения экранов, потому что это возможно это то, что вам нужно, учитывая, для чего используется awk.
pass bash variables to awk using '-v'. –
Он работает для первого параметра, если я использую awk -v line = $ nLine 'NR == line ..Но, похоже, это не работает для второго. В самом деле. awk -v line = $ nLine second = $ 2 'NR == line {$ 0 = "new text second"} 1' test.xml не работает должным образом. – ogs
Вы пробовали 'awk -v line = $ nLine -v second = $ 2 'NR == line {$ 0 =" new text "second} 1' test.xml'? В любом случае, ответ на ваш [другой вопрос] (http://stackoverflow.com/questions/32863518/bash-inexplicable-behavior-sed), вероятно, делает этот вопрос ненужным. –