web-dev-qa-db-ja.com

awkのコマンドライン引数

Awkでif条件を実装したいだけです。以下のように「simple_if」というファイル名を作成しました。

BEGIN{
num=$1;
if (num%2==0)
printf "%d is Even number.\n",num;
else printf "%d is odd Number.\n",num
}

次に、以下のように$ 1の引数として10を渡してプログラムを実行しました

awk -f simple_if 10

しかし、それは入力をとらず、代わりに0を表示します。出力:

0 is Even number.

Awkでユーザーから値を取得する方法は?

7
Dip

コマンドラインの最後でawkに指定された引数は、通常、awkスクリプトが読み取るファイル名として解釈されます。コマンドラインで変数を設定するには、-v variable=valueを使用します。

awk -v num=10 -f script.awk

これにより、numをスクリプトの変数として使用できるようになります。上記の例では、変数の初期値は10です。

スクリプトでENVIRON["variable"]を使用して環境変数を読み取ることもできます(variableという名前の環境変数の場合)、またはARGV[n]を使用してコマンドライン引数を確認することもできます。ここで、nは正の整数。


awk$1を使用すると、現在のレコードの最初のフィールドの値を参照できますが、BEGINブロックで使用しているため、データはまだありません任意のファイルから読み取ります。

コード内の数値は、算術コンテキストで使用される空の変数であるため、ゼロとして解釈されています。

15
Kusalananda

$1は最初のコマンドライン引数ではなく、FSで行が分割された後の最初のフィールドです(行が分割されなかったため、BEGINは空の文字列になります)まだ)。

コマンドライン引数は配列ARGVにあります:

$ awk 'BEGIN { for(i = 1; i < ARGC; i++) print ARGV[i] }' 1st 2nd 3rd
1st
2nd
3rd

ARGV[0]は常にインタープリターの名前です(awkまたはgawkなど)。

awkにコマンドライン引数を無視させ、後でファイルとして開かないようにするには、削除するか、空の文字列に設定する必要があります。 ARGV[1]=""

補足として、var=valueという形式の引数もawkによる変数割り当てとして解釈され、評価されますafter先行するファイル引数処理されました:

$ echo yes > file
$ awk '{ gsub(/e/, var); print }' var=1 file var=2 file var=3 file
y1s
y2s
y3s

key=valという形式の実際のファイル名をawkとともに使用するには、相対パスまたは絶対パスとして渡す必要があります。 awk '{...}' ./key=val

11
mosvy

すでに指摘したように、BEGINセクションでは入力が読み込まれていません。最初の入力行を確認してstdinに番号を指定すると、コードを期待どおりに実行できます。

echo 10 | awk 'NR==1{
num=$1;
if (num%2==0)
printf "%d is Even number.\n",num;
else printf "%d is odd Number.\n",num
}'
10 is Even number.
1
RudiC

通常のAwkは、GNU gawk固有の動作、パイプ、またはリダイレクト(<)、または-v(変数の割り当て)オプション。

入力引数の処理、ARGC(引数 count 、整数)、およびARGV(引数 vector、「リスト」の別の単語)はすべて the manual で詳細に説明されています。

Mosvyは、背景を説明し、ARGVを解析するために何を実行する必要があるかを要約した素晴らしい仕事をしました。これは、macOSとGNU/Linuxの両方でテストされた、スタンドアロンのシェルスクリプトとして実装された元の目的です。

simple_if.awk

#!/usr/bin/awk -f
##
##  simple_if - tell user if a number given as an argument is even or odd
##
##  Example:    ./simple_if.awk 11
##
BEGIN {
    num = ARGV[1];

    # if you expect to arguments AND read from one or more input files, you need
    # to remove the arguments from ARGV so Awk doesn't attempt to open them as
    # files (causing an error)
    #ARGV[1] = "";

    if (num % 2 == 0) {
        printf "%d is an even number.\n", num;
    } else {
        printf "%d is an odd number.\n", num;
    }
}

このようなAwkスクリプトを作成します 実行可能 with chmod a+x scriptname.awk、それを$PATHに入れます。他のBash、Python、Perlスクリプト、Cプログラムなどと同様に実行できます。

システムの他の場所にawkが存在する場合は、#!行を適切に更新してください。 awk must にはスクリプトを実行するための/usr/bin/envオプションがあり、… であるため、-fを使用できない場合があります。複雑です

.awk拡張子は必要ありませんまったくですが、エディターが適切な構文強調表示を有効にするのに役立つ場合があります。オフのままにしておくと、Awkスクリプトであることを誰も知る必要はありません。


以下は、有用な処理を行い、妥当なエラー処理を行う、より完全な例です。

simple_stats.awk

#!/usr/bin/awk -f
##
##  simple_stats - do simple 1-variable statistics (min/max/sum/average) on
##                 the first column of its input file(s)
##
##  examples:      ./simple_stats min numbers.txt
##                 ./simple_stats all numbers.txt    # all stats
##                 ./simple_stats sum <(du MyFiles)  # Bash proc. substitution
##
##                 # specify '-' as the filename when reading from stdin
##                 seq 1 100 | ./simple_stats avg -
##
BEGIN {
    # expect stats operation as the first argument
    op = ARGV[1]

    # unset this array index so Awk doesn't try opening it as a file later
    # ref: https://www.gnu.org/software/gawk/manual/html_node/ARGC-and-ARGV.html
    ARGV[1] = ""  

    # if you wanted to process multiple command line arguments here, you could
    # loop over ARGV, using something like
    # for (i=0; i<ARGC; i++) { if (ARGV[i] == "...") { ... } }

    if (op !~ /^(min|max|sum|avg|all)$/) {
        print "ERROR: Expected one of min/max/sum/avg/all." >"/dev/stderr"
        # 'exit' in BEGIN will always run the EXIT block, if one exists
        # see https://www.gnu.org/software/gawk/manual/html_node/Assert-Function.html
        _assert_exit = 1
        exit 1
    }

    # ordinarily Awk reads stdin without specifying; here, '-' seems necessary
    if (ARGV[2] == "") {
        print "ERROR: Need an input file (or '-' for stdin)." >"/dev/stderr"
        _assert_exit = 1
        exit 1
    }
}

# 'min' needs an initial value so take the first record
NR == 1 { min = $1 }

# for every input line (including the first)...
{
    sum += $1
    if ($1 > max) max = $1
    if ($1 < min) min = $1
}

END {
    if (_assert_exit) exit 1;  # if 'exit' was pending from BEGIN block

    if (op == "min" || op == "all")
        printf "The minimum is: %15d\n", min
    if (op == "max" || op == "all")
        printf "The maximum is: %15d\n", max
    if (op == "sum" || op == "all")
        printf "The sum is:     %15d\n", sum
    if (op == "avg" || op == "all")
        printf "The average is: %15.2f\n", sum/NR
}
0
TheDudeAbides