Grep / awkは複数のファイルを単一の出力に変換します。

Grep / awkは複数のファイルを単一の出力に変換します。

grep現在のテキスト文字列を検索し、awk必要な変数をフィルタリングするために使用するデータを含むいくつかのtxtファイルがあります。文字列がファイル内で繰り返されるので、現在このコマンドを使用して目的の文字列を抽出しています。

grep 'text' *.txt | awk ' NR==1  {print $2 } ' > outputfile

問題は、フォルダ内の複数のファイルを繰り返し、抽出された変数を各ファイルの単一の出力ファイルに書きたいということです。この質問に対する回答は以前にすでに回答されていることがわかっていますが、これは初めてであり、実装するのが困難です。

どんなフィードバックでも大変感謝します!

答え1

各反復の出力を別の出力ファイルにリダイレクトできるように、各ファイルのファイル名を保持しながらbash内のファイルを繰り返します。

たとえば、次のようになります(テストされていません)。

PREFIX="/tmp/outputs"   # define where to store all the outputs
mkdir -p "${PREFIX}"    # make sure the outputs dir exists

for FILE in *.txt       # get the file names you want to work on
do
  # use ${PREFIX}/${FILE} to redirect output to a 
  # file that's associated with the input
  grep 'text' "${FILE}" | awk ' NR==1 {print $2 } ' > "${PREFIX}/${FILE}"
done

答え2

.txt私が正しく理解したら、各ファイルに対して次のことを行う必要があります。

  • パターンを含む最初の行を見つけますtext
  • この行では、スペースで区切られた2番目のフィールドを入力ファイルに関連付けられている名前のファイルに書き込みます。

出力ファイル名の設定方法は説明していません。入力ファイルと同じに.outしますが.txt

シェルループを使用してこれを行うことができます。

for x in *.txt; do
  grep 'text' -- "$x" | awk '{print $2; exit}' >"${x%.*}.out"
done

読み続けるように指示し、何もしないよりも、作業が完了した直後にawkを終了する方が高速です。もう1つの可能性は、awkを完全にスキップし、シェルに行分割を実行させることです(これがより速いか遅いかは、多くの要因によって異なり、予測に危険を与えません)。

for x in *.txt; do
  grep 'text' -- "$x" | read -r first second rest && printf '%s\n' "$rest" >"${x%.*}.out"
done

別のアプローチは、すべてのタスクをawkで実行することです。 awkは複数のファイルで動作でき、awkの出力リダイレクトを使用できます。これには少ないプロセスが必要です。 Gawk(GNU awk)では非常に簡単です。

awk '/text/ {print $2 >substr(FILENAME, 1, length(FILENAME)-4) ".out"; nextfile}' *.txt

awk実装がない場合は、nextfile次のファイルへの変換を手動で処理する必要があるため、このアプローチはあまり魅力的ではありません(より複雑で効率的ではありません)。

awk '
    FNR==1 {first=1}
   first && /text/ {print $2 >substr(FILENAME, 1, length(FILENAME)-4) ".out"; first=0}' *.txt

関連情報