Подтвердить что ты не робот

Установить переменную в текущей оболочке из awk

Есть ли способ установить переменную в текущей оболочке из awk?

Я бы хотел обработать файл и распечатать некоторые данные; так как я прочитаю весь файл, я бы хотел сохранить количество строк - в этом случае FNR.

Бывает, хотя я не могу найти способ установить переменную оболочки с FNR значением; Если бы не это, мне пришлось бы прочитать FNR из моего выходного файла, чтобы установить, скажем num_lines, с FNR значением.

Я пробовал несколько комбинаций с помощью awk 'END{system(...)}', но не мог заставить его работать. Как это обойти?

4b9b3361

Ответ 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.