awkのスラープモード?


16

ツールが好きsedawkまたはperl -nその入力一つのプロセスレコードを一度に、レコードがされてデフォルトでは。

いくつかは、同様にawkしてRS、GNU sed-zperlとは-0ooo別のレコードセパレータを選択することで、レコードの種類を変更することができます。

perl -nオプションを使用して、入力全体(複数のファイルを渡した場合は各ファイル)を単一のレコードにすることが-0777できます(または-0、0377より大きい任意の8進数が続きます。777は正規のものです)。それが彼らがスラープモードと呼ぶものです

似たようなことをawks RSまたは他のメカニズムで実行できますか?どこでawk各プロセスのファイルごとに対立するものとしての順序で、全体としてのコンテンツをライン各ファイルの?

回答:


15

単一の文字(従来の実装のように)としてawk扱うか、正規表現(like またはdo)RSとして扱うかに応じて、異なるアプローチを取ることができます。空のファイルは、スキップする傾向があると見なされるのも難しいです。awkgawkmawkawk

gawkmawkまたは正規表現になりうる他のawk実装RS

これらの実装では(のためのmawkDebianのようないくつかのOSは非常に古いバージョンの代わりに、出荷することに注意してください、@ThomasDickeyによって維持近代的なものを)、あればRS単一の文字が含まれているレコードセパレータは、その文字である、またはawkとき段落モードに入りRS、空でありますRSそれ以外の場合は正規表現として扱います。

そこでの解決策は、一致する可能性のない正規表現を使用することです。x^または$xx開始前、または終了後)のように思い浮かぶ人もいます。ただし、一部(特にgawk)は、他よりも高価です。これまでのところ、これが^$最も効率的な方法であることがわかりました。空の入力でのみ一致しますが、一致するものは何もありません。

できること:

awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...

ただし、1つの注意点は、空のファイルをスキップすることです(とは反対perl -0777 -n)。代わりにステートメントにawkコードを入れることで、GNUで対処できますENDFILE。しかし$0、空のファイルを処理した後はリセットされないため、BEGINFILEステートメントでリセットする必要もあります。

gawk -v RS='^$' '
   BEGINFILE{$0 = ""}
   ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...

従来のawk実装、POSIXawk

それらでRSは、たった1文字であり、BEGINFILE/ ENDFILEを持たず、RT変数を持たず、通常はNUL文字を処理できません。

RS='\0'とにかく、NULバイトを含む入力を処理できないため、using は機能すると考えられますが、いいえ、RS='\0'従来の実装ではRS=段落モードであるとして扱われます。

解決策の1つは、などの入力で検出されそうにない文字を使用することです\1。マルチバイト文字ロケールでは$'\U10FFFE'、UTF-8ロケールのように、割り当てられていない文字または非文字を形成するため、発生する可能性が非常に低いバイトシーケンスにすることもできます。しかし、絶対に万全ではなく、空のファイルにも問題があります。

別の解決策は、入力全体を変数に保存し、最後にENDステートメントで処理することです。ただし、一度に処理できるファイルは1つだけです。

awk '{content = content $0 RS}
     END{$0 = content
       printf "%s: <%s>\n", FILENAME, $0
     }' file

それはに相当しsedます:

sed '
  :1
  $!{
   N;b1
  }
  ...' file1

そのアプローチの別の問題は、ファイルが改行文字で終わっていなかった場合(そして空ではなかった場合)、$0最後にまだ任意に追加されているgawkことです(で、RTではなくRS、上記のコード)。1つの利点は、ファイルの行数の記録がNR/にあることFNRです。


最後の部分については(「ファイルが改行文字で終わっていなかった場合(そして空でなかった場合)、最後に$ 0で任意に追加されます」):テキストファイルの場合、末尾にあるはずです改行。たとえば、viはファイルを追加するため、保存するときにファイルを変更します。終了改行がないため、一部のコマンドは最後の「行」(例:wc)を破棄しますが、他のコマンドはまだ最後の行を「表示」します... ymmv。したがって、テキストファイルを処理することになっている場合、ソリューションは有効です(おそらく、awkはテキスト処理には適していますが、バイナリにはあまり適していません^^)
Olivier Dulac

1
すべてを丸lurみしようとすると、いくつかの制限にぶつかる可能性があります...従来のawkには、行に99フィールドの制限があったようです(したがって?)また、1行の合計の長さ(または1行ですべてを管理する場合は全体)の長さに制限がありますか?
オリビエデュラック

最後に:(愚かな...)ハックは、最初にファイル全体を解析し、そこにないcharを探しtr '\n' 'thatchar' てから、awkに送信する前にファイルとtr 'thatchar' \n'出力を探す ことですか?(上記で述べたように、入力ファイルに終了改行{ tr '\n' 'missingchar' < thefile ; printf "\n" ;} | awk ..... | { tr 'missingchar' '\n' }があることを確認するために、まだ改行を追加する必要があるかもしれません:( しかし、最後に '\ n'を追加します。最終trの前にsedを追加しますか?そのtrが改行を終了せずにファイルを受け入れる場合...)
オリビエデュラック

@OlivierDulac、フィールド数の制限は、NFまたは任意のフィールドにアクセスしている場合にのみヒットします。awk分割しないと分割しません。とはいえ、/bin/awkSolaris 9(1970年代のawkに基づく)にもそのような制限はなかったので、そうなるものを見つけることができるかどうかわかりません(SVR4のoawkには99とnawk 199の制限があったので、まだ可能です)その制限の解除はSunによって追加された可能性が高く、他のSVR4ベースのawksにはない可能性があります。AIXでテストできますか?)。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.