ワイルドカード入力に新しいファイル名を書き込むには?

ワイルドカード入力に新しいファイル名を書き込むには?

私は科学インターンシップの間に主にいくつかのユーティリティを使用してInixターミナルを使用した経験を得ましたがgrep、私がしなければならない数字をより効率的に処理できるようにしばらく見つけようとしました。 。awksed

run.awk多数のテキストファイルに対していくつかのタスクを実行するスクリプトがあります。実際にファイルをインポートしてchloride.outデータを抽出して作成しますchloride.cm

とにかく、このスクリプトにシェルの初期ワイルドカードフレーズに基づいてファイルを受信して​​書き込むことができますか*.out*.cm

大量のデータを処理するために作成したスクリプトの数が100回を超え、本当に迷惑です。

理想的には、すべてのスクリプトに対してシェルを介してこれを行う方法があるかどうかを知りたいです。シェルまたはそれに対応するツールで自動化できない場合は、少なくともawk私が説明したのと同様の方法でスクリプトを自動化できますか?

答え1

もちろん、awkにワイルドカードを介して複数のファイルを処理させることもできます。 1つの提案は、これをrun.awk単一のファイルを受け入れ、単一の出力ファイルを生成する一般的な「関数」に保ち、入力と出力ファイルの同化を担当できる他のスクリプトから呼び出すことです。

はい

これはBashスクリプトになり、と呼ぶことができますawk_runner.bash

#!/bin/bash

for ifname in *.out; do 
  ofname=${ifname/.out/.cm}
  printf "IN: %s, OUT: %s\n" $ifname $ofname
  printf "running run.awk with %s & %s\n\n" $ifname $ofname

  run.awk $ifname $ofname
done

サンプルの実行

いくつかのテストファイルを含むサンプルディレクトリを作成しました。

$ touch file{1..4}.out

その結果、4つのファイルが作成されました。

$ ls -1
file1.out
file2.out
file3.out
file4.out

これでスクリプトを実行します。

$ ./awk_runner.bash
IN: file1.out, OUT: file1.cm
running run.awk with file1.out & file1.cm

IN: file2.out, OUT: file2.cm
running run.awk with file2.out & file2.cm

IN: file3.out, OUT: file3.cm
running run.awk with file3.out & file3.cm

IN: file4.out, OUT: file4.cm
running run.awk with file4.out & file4.cm

「running...」で始まる各行の後にスクリプトをここで実行できます。

リスト内のファイル

ワイルドカードを使用する代わりに、*.outファイル名のリストを含むファイルを使用するとします。例:

$ cat filelist.txt 
file1.out
file2.out
file3.out
file4.out

whileループの代わりにループを使用する変更されたバージョンのスクリプトを使用できますfor。さて、このスクリプトのバリエーションを次のように呼びましょうawk_file_runner.bash

#!/bin/bash

while read ifname; do 
  ofname=${ifname/.out/.cm}
  printf "IN: %s, OUT: %s\n" $ifname $ofname
  printf "running run.awk with %s & %s\n\n" $ifname $ofname

  run.awk $ifname $ofname
done < filelist.txt

このバージョンのスクリプトはファイルから入力を読み取りますfilelist.txt

done < filelist.txt

その後、ループが繰り返されるたびにコマンドを使用して入力ファイルから1行を読み取りますwhileread

while read ifname; do

awk次に、ファイルの各行を繰り返しながらスクリプトを実行する最初のスクリプトと同じ方法ですべての操作を実行します。run.awk

答え2

シェルラッパーを作成して処理するファイルごとに新しいawkインスタンスを作成するのではなく、awkから直接これを実行できます。 awkスクリプトがすでに存在する場合は、FILENAME変数を使用して現在のファイルにアクセスできます。したがって、を実行すると、awk 'some commands' file1 file2FILENAMEを使用してfile1を使用しているかfile2を使用しているかを確認できます。>on / in awkを使用することもできますprintprintfしたがって、このようなawkスクリプトがあれば

/pattern/{ print $1,$3 }

君は簡単にできる

/pattern/{ print $1,$3 > FILENAME".processed" }

または、それを使用してFNR=1新しいファイルのタイミングを知らせ、ファイル名でより複雑な操作を実行する変数を作成します。.in拡張を次.outのように置き換えるのと同じです。

sauer@humpy:/tmp$ grep . file*.in
file1.in:a
file1.in:b
file2.in:c
sauer@humpy:/tmp$ awk 'FNR=1{out=FILENAME;sub("\.in$",".out",out)} {print "processed"$0 > out}' file*.in
sauer@humpy:/tmp$ grep . file*.out
file1.out:processeda
file1.out:processedb
file2.out:processedc

私はこれを使ってgrep .ここにファイル名と複数のファイルの内容を表示しますが、これも興味深いトリックです。ただし、変数の値をout1に変更した場合は、変更されたバージョンに設定して(ファイルの行1にある)、すべての印刷にリダイレクトすることが重要です。拡張子はそうではないので少し危険です。一致すると、置き換えが行われず、入力ファイルが上書きされます。したがって、これを確実にするために安全装置検査を追加することをお勧めします。これは読者に練習問題として残す。 ;)FILENAMEFNRoutout != FILENAME

ファイル名のリストを含むファイルが必要な場合、最も簡単な方法は次のように実行することです。

awkscript $(< /path/to/filename_list_file )

コンテンツをインポートしてfilename_list_fileコマンドラインに配置します。

関連情報