AWK:外部ユーティリティに渡された引数がフィールド分割されるのを防ぎます。

AWK:外部ユーティリティに渡された引数がフィールド分割されるのを防ぎます。

AWKスクリプト内では、変数を外部ユーティリティに引数として渡すことができます。

awk 'BEGIN {
    filename = "path_to_file_without_space"
    "file " filename | getline
    print $0
}'

ただし、変数にスペースが含まれている場合

awk 'BEGIN {
    filename = "path to file with spaces"
    "file " filename | getline
    print $0
}'

エラーが発生しました。

file: cannot open `path' (No such file or directory)

シェルが空白で引用しない変数を分割する方法と同様に、空白から引数を分割することをお勧めします。次のように、シェルのIFSをnullに設定してシェルフィールド分割を無効にしたいと思います。

"IFS= file " filename | getline

あるいは、AWK コマンドを実行する前に IFS を null に設定しましたが、両方のオプションに違いはありません。このフィールド分割を避ける方法は?

ベストアンサー1

ファイル名を引用する必要があります。

awk 'BEGIN {
    filename = "path to file with spaces"
    "file \"" filename "\"" | getline
    print
}'

またはコメントで提案されているように読みやすくするため

awk 'BEGIN {
    DQ = "\042" # double quote (ASCII octal 42)
    filename = "path to file with spaces"
    "file " DQ filename DQ | getline
    print
}'

またはこれがawkより大きなプログラムの一部であると仮定すると、

BEGIN {
    SQ = "\047"
    DQ = "\042"
}

BEGIN {
    name = "filename with spaces"
    cmd = sprintf("file %s%s%s", DQ, name, DQ)

    cmd | getline
    close(cmd)

    print
}

つまり、オープンファイルハンドルの保存が完了したら、コマンドを閉じます。別のブロックに便利な「定数」を設定しますBEGIN(これらのブロックは順次実行されます)。別の変数を使用してコマンドを作成しますsprintf。 (この内容のほとんどは、明らかにメンテナンスawkのために読みやすい構造を提供する必要があるより長いまたは複雑なプログラムを対象としています。dquote()文字列を参照して関数を書くことを想像することもできます。)squote()

「パイプ」の左側はリテラル文字列として評価されます。

file "path to file with spaces"

デフォルトでは、usingは文字列である単一のパラメータを使用cmd | getlineしてawk呼び出します。したがって、実行を使用するには文字列を正しく引用する必要があります。sh -ccmdsh -c

技術的な詳細については、以下を参照してください。POSIX規格:

expression | getline [var]

コマンド出力がパイプされるストリームから入力レコードを読み取ります。ストリームが現在開いていない場合は、expressionコマンド名として値を使用して生成する必要があります。生成されたストリームは、popen()式の値をコマンド引数に、値を引数としてr関数を呼び出して生成されたストリームと同じでなければなりませんmode。ストリームが開いている限り、expression同じ文字列値で評価される後続の呼び出しは、ストリームから後続のレコードを読み取る必要があります。close同じ文字列値で評価される式を使用して関数が呼び出されるまで、ストリームは開いたままにする必要があります。そのとき、この関数を呼び出したかのようにストリームが閉じられますpclose()var省略すると設定され、そうでなければ設定さ$0れ、該当する場合は数値文字列として扱われます(awkの式を参照)。NFvar

popen()ここで言及される関数はCライブラリpopen()関数である。これは実行のために与えられた文字列を予約しますsh -c

system()スペースを含むファイル名でコマンドを実行すると、まったく同じ問題が発生しますが、この場合はsystem()Cライブラリの関数が呼び出されます。返品呼び出しsh -c方法は似ていますpopen()(ただし、I/O ストリームのパイプラインは異なります)。

したがって、単一の引数で呼び出すと設定はIFS役に立ちません。sh -c

file path to file with spaces

おすすめ記事