awkスクリプトを書くには?

awkスクリプトを書くには?

スタンドアロンawkスクリプトファイルを作成する方法を理解しようとしています。

スタンドアロンのbashスクリプトファイルに似ていると思います。

#! /usr/bin/awk -f      
BEGIN{
    for  (i  =  0;  i  <  ARGC;  i++)
        printf  "%s  ",  ARGV[i]
    printf  "\n"
}
{print $0}
  1. シェルでコマンドライン引数を指定し、それをスクリプトに渡す方法を見つけようとしています。

    $ myscript.awk arg1 arg2 arg3
    awk  arg1  arg2  arg3  
    awk: /home/tim/myscript.awk:5: fatal: cannot open file `arg1' for reading (No such file or directory)
    

    awkスクリプトにはどのコマンドライン引数が必要ですか?arg1 入力ファイルになると予想されるのはなぜですか?

    コマンドライン引数はawkスクリプトに渡され、ARGV配列に格納されます。私のアップデートをご覧ください。だからコマンドライン引数はawk

  2. -fshebangを削除すると、つまり#! /usr/bin/awk

    $ myscript.awk arg1 arg2 arg3
    awk: cmd. line:1: /home/tim/myscript.awk
    awk: cmd. line:1:                   ^ syntax error
    

    なぜ-f必要ですか?

ありがとうございます。

答え1

AWKは、引数がスクリプトのテキストであるか、-f実行されるスクリプトを含むファイル名が続くことを期待しています。どちらの場合も、オプションで処理するファイル名が続きます。

これがshebang行が必要な理由を説明します-f。この行がなければ、AWKはスクリプトのファイル名自体が実行されるAWKステートメントだと思います。

パラメータ処理に関して、AWKプログラムは必要に応じて独自のパラメータ処理を実行できます。次の行でスクリプトが{print $0}失敗します。これは、インタプリタが入力(一部指定したため、コマンドラインに名前が付けられたファイル)から各行を読み取り、ブロックの指示に従って処理するように指示します。その行を削除するとエラーは発生しません。パラメータを処理して入力ファイルのみを含めるようにBEGIN削除すると、AWKは文句を言いません。ARGV

独自のパラメータと入力処理を試みることは、AWKを非常に便利にする多くのものを無視することを意味できます。そうしたい場合は、Perlを使用することをお勧めします。

(shebang処理は単純なAWKスクリプトをファイル名に保存できることを意味するので、スクリプトの賢い名前を見つける必要はありません。誰もそうしないでください...)

答え2

awkスクリプトにはどのコマンドライン引数が必要ですか?なぜarg1を入力ファイルとして期待するのですか?

awkパターンベースのルールには入力が必要です。プログラムのこの部分の処理が開始されると、引数がawkファイル名として使用されます(ファイル名が指定されていない場合は標準入力が使用されます)。

このステップの前に、ブロックに指定されたパラメータを使用してすべての操作を実行できますBEGIN

次のような小さな例があなたの始めに役立つと思います。

$ cat a.awk 
#!/usr/bin/awk -f
BEGIN {
        i=1
        while( i in ARGV )
                print ARGV[i++]
}

a.awkブロックは1つだけで、BEGINパターンベースのルールはありません。awkファイルは必要ないので、与えられた引数はファイル名として使用されません。

$ ./a.awk poit --zort -troz narf
poit
--zort
-troz
narf

これで何をするかはあなたの決断です。

パターンベースのルールを介してパラメータとして提供されたファイルを処理するには、ブロックで使用されているすべてのパラメータを削除する必要がありますBEGIN

$ cat b.awk 
#!/usr/bin/awk -f
BEGIN {
        if( ARGV[1] == "--tolower" ) { cmd = "tr A-Z a-z" ; delete ARGV[1] }
        else if( ARGV[1] == "--toupper" ) { cmd = "tr a-z A-Z" ; delete ARGV[1] }
        else cmd = "cat"
}
{
        print | cmd
}

オプションなしで例を実行します。

$ ./b.awk a.awk
#!/usr/bin/awk -f
BEGIN {
        i=1
        while( i in ARGV )
                print ARGV[i++]
}

オプションを使用して例を実行します--toupper

$ ./b.awk --toupper a.awk
#!/USR/BIN/AWK -F
BEGIN {
        I=1
        WHILE( I IN ARGV )
                PRINT ARGV[I++]
}

答え3

スクリプトは、awkオプションではなく、コマンドライン引数がスクリプトが機能する必要があるファイルのファイル名であると予想します(何も指定されていない場合は標準入力として機能します)。

したがって、スクリプトファイル#!/usr/bin/awk -fでこれを使用すると、awkファイル自体のテキストをに渡す必要があることをシステムに通知しますawk -f。他のコマンドライン引数は入力ファイルまたは追加フラグとして解釈されますawk

#!/usr/bin/awk -f

BEGIN {
    for (i in ARGV) {
        printf("ARGV[%d] = %s\n", i, ARGV[i]);
    }
    printf("var = %s\n", var);
}

$ ./script.awk -vvar=hello ~/.profile
ARGV[0] = awk
ARGV[1] = /home/kk/.profile
var = hello

オプションのコマンドラインチェックは、オプションではなく最初の引数で終わります。

$ ./script.awk ~/.profile -vvar=hello
ARGV[2] = -vvar=hello
ARGV[0] = awk
ARGV[1] = /home/kk/.profile
var =

何でも便利に使用するにはawk入力データが必要です。このデータは通常、コマンドラインで指定された1つ以上の入力ファイルまたは標準入力ストリームから送信されたデータから取得されます。

BEGINANDブロックを除いて、ENDスクリプトの各ブロックはawk入力データの各レコードに順番に適用されます(デフォルトは各行)。

関連情報