2013-01-24 2 views
13

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

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

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

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

ответ

16
$ echo "$var" 

$ declare $(awk 'BEGIN{print "var=17"}') 
$ echo "$var" 
17 

Вот почему вы должны использовать объявить вместо 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 отпечатки, которые могут случайно оказаться очень плохо!

+0

+1 за рекомендацию, но пока я пишу код, я не вижу проблемы с использованием 'eval'. – Rubens

+10

@ Рубенс, до того дня, когда вы случайно сделаете что-то плохое. Если у вас есть привычка писать безопасный код сейчас, вы не будете укусаться в будущем. –

+0

@glennjackman +1 спасибо за подсказку; Я думаю, именно поэтому безопасное кодирование рассматривается здесь (: – Rubens

1

сделать awk распечатать оператор присваивания:

MYVAR=NewValue 

Затем в сценарии оболочки, eval вывод вашего awk сценария:

eval $(awk ....) 
# then use $MYVAR 

EDIT: люди рекомендуем использовать declare вместо eval, быть немного менее подверженным ошибкам, если внутренний сценарий будет напечатан, кроме присваивания. Это только bash, но это нормально, когда оболочка равна bash, а сценарий имеет #!/bin/bash, правильно указав эту зависимость.

Вариант eval $(...) широко используется с существующими программами, генерирующими выход, подходящий для eval, но не для declare (lesspipe - пример); поэтому важно понять это, и вариант, основанный только на bash, «слишком локализован».

+0

Это единственный технически возможный ответ – anishsane

+0

@anishsane Кажется разумным мне (:.! Не могли бы думать об этом, хотя Спасибо, Антон Коваленко – Rubens

+0

Я хотел бы использовать 'declare' вместо' eval' – chepner

4

Вы не можете экспортировать переменные из подоболочки в свою родительскую оболочку. У вас есть какие-то другие варианты, хотя, в том числе:

  1. Сделать еще один проход файла, используя AWK для подсчета записей, и использовать подстановки команд, чтобы захватить результат. Например:

    FNR=$(awk 'END {print FNR}' filename) 
    
  2. печати FNR в субоболочке и разобрать вывод в вашем другом процессе.
  3. Если FNR - это то же самое, что и количество строк, вы можете позвонить по телефону wc -l < filename, чтобы получить ваш счет.
+0

2-й и 3-й варианты - это то, чего я пытаюсь избежать, но на самом деле я не понял эту идею из первой. Разве это не первая такая же техника, которую я бы использовал в третьей? – Rubens

+0

Yep, 'FNR = $ (awk 'END {print FNR}' filename)' и 'FNR = $ (wc -l filename | awk '{print $ 1}')' совершенно одинаковы, за исключением одного подсчета программы строки - 'awk' /' wc'. – Rubens

+3

вы бы не сделали эту комбинацию wc + awk, но вместо этого вы просто сделаете 'wc -l

14

Вот еще один способ.

Это особенно полезно, когда, когда вы получили значения ваших переменных в одной переменной, и вы хотите разделить их. Например, у вас есть список значений из одной строки в базе данных, из которой вы хотите создать переменные.

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 

Нам понадобится «здесь строки», т.е. < < < в этом случае, поскольку команда чтения не читает из трубы, и вместо этого читает из стандартного ввода

+2

Это было именно то, что мне нужно! У меня уже есть var с строками, разделенными пробелами, поэтому я просто дал это во входных (например, в «read abc <<< $ var». Спасибо –

+0

<3 .. спасибо за это. – calbertts

+0

одно можно упомянуть, если поля разделены пробелом, это может быть упрощено с помощью: '' ' читать abc < << $ (echo $ {val}) '' ' –

3

предупреждение для тех, кто пытается использовать объявить предложенные несколькими ответами.

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. 
1

синтезировать все здесь до сих пор я поделюсь, что я нахожу полезным установить переменную среды оболочки из скрипта, который читает однострочный файл с помощью awk. Очевидно, можно использовать /pattern/ вместо NR==1, чтобы найти нужную переменную.

# 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.

Смежные вопросы