web-dev-qa-db-ja.com

awkから現在のシェルに変数を設定する

awk内から現在のシェルに変数を設定する方法はありますか?

ファイルに対して何らかの処理を行い、データを出力したいと思います。ファイル全体を読み通すので、行数(この場合はFNR)を保存したいと思います。

FNR値を使用してシェル変数を設定する方法を見つけることができないようですが、どうなりますか。そうでない場合は、出力ファイルからFNRを読み取って、FNRの値で_num_lines_を設定する必要があります。

awk 'END{system(...)}'を使用していくつかの組み合わせを試しましたが、機能するように管理できませんでした。これを回避する方法はありますか?

18
Rubens
$ echo "$var"

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

Evalの代わりにdeclareを使用する理由は次のとおりです。

$ 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が出力する文字列を実行することに注意してください。これは偶然非常に悪いことです。

24
Ed Morton

別の方法があります。

これは、変数のvaluessingle変数で取得し、分割したい場合に特に便利です。たとえば、変数を作成するデータベースの単一行の値のリストがあります。

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

Readコマンドはパイプから読み取らず、代わりにstdinから読み取るため、「here string」、つまりこの場合は<<<が必要です。

21
Nerrve

サブシェルからその親シェルに変数をエクスポートすることはできません。ただし、次のような他の選択肢もあります。

  1. AWKを使用してファイルの別のパスを作成してレコードをカウントし、コマンド置換を使用して結果をキャプチャします。例えば:

    FNR=$(awk 'END {print FNR}' filename)
    
  2. サブシェルで[〜#〜] fnr [〜#〜]を出力し、他のプロセスで出力を解析します。
  3. [〜#〜] fnr [〜#〜]が行数と同じ場合、wc -l < filenameを呼び出してカウントを取得できます。
4
Todd A. Jacobs

いくつかの答えが示唆するように、宣言を使用しようとする人への警告。

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.
3
sbts

awkで割り当てステートメントを出力します。

_MYVAR=NewValue
_

次に、シェルスクリプトで、evalawkスクリプトの出力:

_eval $(awk ....)
# then use $MYVAR
_

編集:人々はdeclareの代わりにevalを使用することを推奨します。これは、割り当て以外の何かが内部スクリプトによって出力された場合にエラーが発生しにくくなります。 bashのみですが、シェルis bashで、スクリプトに_#!/bin/bash_が含まれていて、この依存関係が正しく記述されている場合は問題ありません。

eval $(...)バリアントは広く使用されており、既存のプログラムはevalに適した出力を生成しますが、declareには適しません(lesspipeは例です)。それがそれを理解することが重要である理由であり、bashのみのバリアントは「ローカライズされすぎています」。

1
Anton Kovalenko

ここまでですべてを合成するには、awkを使用して1行のファイルを読み取るスクリプトからシェル環境変数を設定するのに便利だと思うことを共有します。明らかに、必要な変数を見つけるために/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のセキュリティリスクが回避されます。

1
Merlin

echo(First arg:$ 1 "for((i = 0; i <$ 1; i ++)); echo "inside" echo "Welcome $ i times。" cat man.xml | awk '{x [NR] = $ 0} END {for(i = 2; i <= NR; i ++){if(x [i]〜//){x [i + 1] = "' $ i '" } print x [i]}} '> $ i.xml done echo "compleated"

0
Hari Prassana