パイプを介してインタラクティブにawkを使用する

パイプを介してインタラクティブにawkを使用する

見ているこの問題awk、ファイルが標準入力にパイプされていると、ユーザー入力を読み取ることはできませんが、コマンドライン引数として指定されたファイルから入力を読み取ることが期待どおりに機能することを確認しました。

たとえば、スクリプトに次のBEGINブロックがあるとしますawk

BEGIN {
    printf "Enter input: "
    getline var < "-"
}

これを実行すると、awk -f ./script.awk file.txtユーザーに入力するように求められ、処理が続行されますfile.txt。ただし、これを実行すると、cat file.txt | awk -f ./script.awkawkがパイプから取得した内容をユーザー入力として解釈すると考えられます(したがって、最初の行がgetline埋められます)。varfile.txt

awkファイルから読み取るように動作しますが、パイプで使用する方法はありますか?

もちろん、一時ファイルを使用することもできますが、これはエレガンスから離れています。

答え1

プロセスの置き換えは簡単な場合には機能しますが、パイプデータを処理しながらコンソールユーザーと対話できる一般的なアプローチは次のとおりです。

BEGIN {
    printf "Enter input: " > "/dev/tty"
    getline var < "/dev/tty"
    print var
}

答え2

一時ファイルに加えて、プロセス置換のためのシェルのサポートを使用することもできます(これはbashzshまたはいくつかの実装ksh(この機能はksh88で導入されている)と仮定します)。

awk -f ./script.awk <(cat file.txt)

これは、読み込み時に添付されたコマンドの出力を含む構文の代わりにawkファイル名を提供します。<(...)

答え3

これがあなたのワークフローに適している場合は、awk自体がパイプを開くようにすることができます。 Elementsではこれを行うことができないため、ARGVパイプから読み取った行からawkの自動反復を取得することはできません。代わりに、awkはコマンドライン引数として渡されたファイルから読み取るか、ファイル引数がない場合は標準入力から読み込みます。

{
    printf "Enter input: "
    getline var
    while (("cat file.txt" | getline) > 0) { … }
}

この構造はあなたのおもちゃの例には合いませんが、実際の問題に合う可能性があるので言及します。

答え4

システムが/dev/fd/[num]接続をサポートするawkかGNUの場合は、次awkのように機能しますawk -f ./script.awk file.txt

{ some_cmd | 3<&0 <&4 4<&- awk -f ./script.awk /dev/fd/3; } 4<&0

関連情報