Установить переменную в текущей оболочке из awk
Есть ли способ установить переменную в текущей оболочке из awk
?
Я бы хотел обработать файл и распечатать некоторые данные; так как я прочитаю весь файл, я бы хотел сохранить количество строк - в этом случае FNR
.
Бывает, хотя я не могу найти способ установить переменную оболочки с FNR
значением; Если бы не это, мне пришлось бы прочитать FNR
из моего выходного файла, чтобы установить, скажем num_lines
, с FNR
значением.
Я пробовал несколько комбинаций с помощью awk 'END{system(...)}'
, но не мог заставить его работать. Как это обойти?
Ответы
Ответ 1
$ echo "$var"
$ declare $( awk 'BEGIN{print "var=17"}' )
$ echo "$var"
17
Вот почему вы должны использовать declare вместо eval:
$ eval $( awk 'BEGIN{print "echo \"removing all of your files, ha ha ha....\""}' )
removing all of your files, ha ha ha....
$ declare $( awk 'BEGIN{print "echo \"removing all of your files\""}' )
bash: declare: `"removing': not a valid identifier
bash: declare: `files"': not a valid identifier
Обратите внимание, что в первом случае eval выполняет любые строковые awk-распечатки, что может быть очень плохой задачей.
Ответ 2
Здесь другой путь.
Это особенно полезно, когда у вас есть значения ваших переменных в переменной single, и вы хотите разделить их. Например, у вас есть список значений из одной строки в базе данных, из которой вы хотите создать переменные.
val="hello|beautiful|world" # assume this string comes from a database query
read a b c <<< $( echo ${val} | awk -F"|" '{print $1" "$2" "$3}' )
echo $a #hello
echo $b #beautiful
echo $c #world
Нам нужна строка "здесь" i.e < < в этом случае, поскольку команда чтения не считывается из канала и вместо этого считывает из stdin
Ответ 3
Вы не можете экспортировать переменные из подоболочки в свою родительскую оболочку. Однако у вас есть другие варианты, в том числе:
-
Сделайте еще один проход файла, используя AWK, чтобы подсчитывать записи и использовать подстановку команд для захвата результата. Например:
FNR=$(awk 'END {print FNR}' filename)
- Распечатайте FNR в подоболочке и проанализируйте вывод в другом процессе.
- Если FNR совпадает с количеством строк, вы можете вызвать
wc -l < filename
, чтобы получить свой счет.
Ответ 4
Предупреждение для тех, кто пытается использовать объявление, как было предложено несколькими ответами.
eval не имеет этой проблемы.
Если awk (или другое выражение), предоставленное для объявления результатов в пустой строке, тогда declare будет выгружать текущую среду.
Это почти наверняка не то, что вы хотели бы.
например: если ваш шаблон awk не существует на входе, вы никогда не будете печатать вывод, поэтому вы получите неожиданное поведение.
Пример этого....
unset var
var=99
declare $( echo "foobar" | awk '/fail/ {print "var=17"}' )
echo "var=$var"
var=99
The current environment as seen by declare is printed
and $var is not changed
Небольшое изменение, чтобы сохранить значение, заданное в переменной awk, и напечатать его в конце, разрешает это....
unset var
var=99
declare $( echo "foobar" | awk '/fail/ {tmp="17"} END {print "var="tmp}' )
echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.
Чтобы показать эту работу с соответствующим шаблоном
unset var
var=99
declare $( echo "foobar" | awk '/foo/ {tmp="17"} END {print "var="tmp}' )
echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.
Ответ 5
Сделайте awk
распечатать инструкцию присваивания:
MYVAR=NewValue
Затем в вашей оболочке script, eval
вывод вашего awk
script:
eval $(awk ....)
# then use $MYVAR
EDIT: люди рекомендуют использовать declare
вместо eval
, чтобы быть немного менее подвержен ошибкам, если внутренний script печатает что-то, кроме присваивания. Это bash -одно, но это нормально, когда оболочка bash, а script имеет #!/bin/bash
, правильно указав эту зависимость.
Широко используется вариант eval $(...)
, при этом существующие программы генерируют вывод, подходящий для eval
, но не для declare
(lesspipe
- пример); поэтому важно понять это, а вариант bash - "слишком локализован".
Ответ 6
Чтобы синтезировать все, что здесь есть, я поделюсь тем, что считаю полезным, чтобы установить переменную среды оболочки из script, которая читает однострочный файл с помощью awk. Очевидно, вместо NR==1
можно использовать /pattern/
, чтобы найти нужную переменную.
# export a variable from a script (such as in a .dotfile)
declare $( awk 'NR==1 {tmp=$1} END {print "SHELL_VAR=" tmp}' /path/to/file )
export SHELL_VAR
Это позволит избежать массивного вывода переменных, если команда declare
выдается без аргумента, а также риски безопасности слепых eval
.