反転効果のあるawkシステムコール

特定のキーワードで囲まれた複数のデータブロックを含むデータファイルがあります(DATAEND)。 awkを使用して、ブロックから取得したファイル名に基づいて、データブロックを個別のファイルに抽出しています。一部のデータブロックは同じ名前を共有しているため、ファイル( “blockname“)が既に存在する場合は、各出力ファイルの名前を整数で変更します。

#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4 

3つの出力ファイルblockname1blockname2、および(最後のファイルに整数が割り当てられていることに注意してください)

#cat blockname1 DATA blockname1 data1 data1 END 

(他のファイルはそれに応じて…)

これで、次のスクリプトが希望どおりに機能します。

awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file 

問題はwhileループにあります。そのシステムコール:

system("test -e " file)は、fileが存在する場合はTRUEであり、

はまだ存在しません。つまり、fileが存在している場合にのみ実行を開始するwhileループです。 (新しい)fileがまだ存在しない場合に中断します。

ただし、(そして、print fileで冗長にします)、整数の接尾辞が増加し、反対のsystem("test !-e " file)は望ましい結果をもたらします。

したがって、これは私が期待したものとはまったく逆の動作をします。

回答

OK、私は考えました:問題はtestの終了ステータスとwhile awkのループ条件。

正のtestコマンドの結果ははTRUEで、負の値は1でFALSEです。

ただし、awk whileループは0をFALSEとして解釈し、1をTRUEとして解釈するため、正反対です。定義。

例として:

awk "{ while ( 0 ) ; { print "0" } }" file 

プロにはなりません

awk "{ while (1) ; { print "1" } }" file 

は無限の1を出力しますが、出力を生成します。

ベストプラクティスしたがって、このような組み合わせでは明示的にする必要があります

while ( system("command") == 0 ) 

または

while ( system("command") == 1 ) 

それぞれ。

私の場合

while ( system("test -e " file ) == 0 ) 

は予想される動作を示しています。

回答

awk system()は、実行したコマンドの終了ステータスを返します。成功した場合は0 、!成功しなかった場合は0。簡単な例として、次のコマンドを実行してみてください。

v = system("date"); 

vは0になります

実行した場合:

v = system("dat"); 

vが127であるか、値が0と異なる可能性があります。datコマンドがないか見つからない場合、OSからエラーが返されます。

回答

私があなたを理解している場合、目標はinput.fileのコンテンツをさまざまなファイルに抽出して、同じ名前のブロックが失われないようにすることです。

それが場合、そして、抽出前にターゲットディレクトリが常に空である場合は、より良い(そしてより速い)解決策があります:

awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file 

このように、awkは「ファイルが存在するかどうかをテストするためだけに、新しいシェルをN回実行する必要はありません。

注:

  • awkのフィールドセパレーターであるため、BEGINブロックは必要ありません。はすでにスペースです。
  • 一重引用符はすでに複数行であるため、行末に"\"は必要ありません。

コメント

  • まあ、私の問題" odd "のwhile状態の動作をよりよく理解していました。しかし、あなたの解決策はかなりきちんとしています-私のかさばるものよりも、ありがとう、私は好きです。 BEGINブロックは、私の異なるファイル形式の残り物です。一般的な例では役に立たなくなるのを忘れていました。バックスラッシュを省略すると、問題が発生しなくなります。これもありがとう。ただし、スクリプトの'の意図については注意が必要です。 n = blocks[block]++; file=block (n? "_" n: "")の部分についてもう少し詳しく説明していただけますか?
  • アルゴリズムは、インデックスが付けられたblocksという1つの配列を使用します。ブロック名で。例"blockname1"の最初のインスタンス:blocks["blockname1"]。 Awkはそのインデックスを見つけ、'が見つからないため、""(これもゼロと見なされます)を想定しています。これで、awkではn = var++{n=var;var++}と同等であるため、n==""blocks["blockname1"]==1。最後に、file=block (n? "_" n: ""){file=block;if(n!="") file+="_" n}と同じです。
  • 私は'文字列が有効なインデックス変数であることを認識していても、これはifステートメントが削減されています-非常に役立ちます。ありがとうございます。 '残念ながら"受け入れられた回答"はここにありません:私にもかかわらず 私の最初のタスクを実行するときにこのアプローチを採用しようとすると、'上記の質問に答えません(whileループの条件の解釈)-このサイトの理解に反しますQ &システム。 それでも、私は多くのことを学びました-もう一度感謝します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です