
行が多く、行ごとに列数が可変なテーブルがあります。
各行で最初のフィールドと2つの文字列のうちの1つを含むすべてのフィールドのみを印刷したい(この場合は、dogとcowという単語を含むすべてのフィールドが必要です)。
たとえば、
A dog999 dog284 cow284 pig383 pig234 cow432 chicken432
B cow394 cow432 cow345 dog983 pig345 chicken532
C dog847 pig357 pig236 cow395 dog496
D dog392 cow237 cow749
希望の出力:
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
これまで私はawkを使用していました。
awk -v OFS='\t' '{for (i = 1; i <= NF; i++) {if ($i ~ /dog/) print $1,$i; else if ($i ~ /cow/) print $1,$i} }' file.txt
ただし、これにより各フィールドに2つの文字列のうちの1つが1行を占有します。
答え1
perl
回避策が大丈夫な場合:
$ cat ip.txt
A dog999 dog284 cow284 pig383 pig234 cow432 chicken432
B cow394 cow432 cow345 dog983 pig345 chicken532
C dog847 pig357 pig236 cow395 dog496
D dog392 cow237 cow749
$ perl -lane 'print join("\t",$F[0],grep {/cow|dog/} @F[1..$#F])' ip.txt
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
-a
入力行をスペースに分割して@F
配列に保存-l
入力から改行文字を削除して印刷するときにもう一度追加してください。join
\t
印刷するとき、$F[0],grep {/cow|dog/} @F[1..$#F]
配列の最初の要素とcow
一致するすべての要素、またはdog
- また利用可能です
perl -lape'$_=join"\t",shift(@F),grep/cow|dog/,@F'
。ここでは配列の最初の要素をshift
削除して返し、結果を に割り当てると最後に無料オプションが印刷されます(ヒント)。@F
$_
-p
スティーブン・チャジェラス)
以下を含まないかcow
無視されるdog
行:
perl -lane 'print join("\t",$F[0],grep {//} @F[1..$#F]) if /cow|dog/' ip.txt
答え2
ほとんど似ていますが、一致するすべての単語について印刷したくないので、最初の値を抽出する必要があります。これを使用してprintf
改行を避けることができます。
awk '{printf "%s",$1
for (i=1;i<=NF;i++)
{
if ($i ~ /dog|cow/) { printf " %s",$i; }
}
print ""
}'
出力は次のとおりです。
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
これは1行に縮小できます。
awk '{printf "%s",$1; for (i=1;i<=NF;i++) { if ($i ~ /dog|cow/) { printf " %s",$i; } } print "" }'
これにより、どの単語にも一致しない行が印刷されます。
E pig sheep
出力されます
E
答え3
$ txr -e '(awk (:let tmp)
(:begin (set ofs "\t"))
(f (set tmp (pop f))
(ff (keep-if #/cow|dog/))
(push tmp f) (prn)))' data
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
分解:
:let
マクロの句はローカル変数を指定します。このマクロは「Awk Paradigm」を実装していますが、使用する前に変数を定義する必要がある型安全言語で実装されています。したがって、(POSIX Awkに似ている)など:begin
の句に加えて、このAwkは語彙範囲マクロで定義された変数も提供します。:end
BEGIN
END
:let
(f (set tmp (pop f)) ...)
条件がある条件付き作業句ですf
。レコードの区切りフィールドリストの場合、空でない場合(と等しくないnil
)、ブール値trueのように機能します。したがって、何もない場合は、ジョブフォームが実行されますf
。(set tmp (pop f))
リストから最初のフィールドをポップして一時変数に保存しますtmp
。 2番目のフィールドが1番目のフィールドになり、3番目のフィールドが2番目のフィールドになる式です。f
レコードは、フィールドを使用してレコードが再編成されるPOSIX Awkと同様に、作業時にrec
自動的に再編成されます。ofs
$0
OFS
(ff ...)
この場合、タスクごとにフィールドをフィルタリングします(keep-if #/regex/)
。デフォルトでは、f
正規表現と一致しないすべてのフィールドを削除します。ff
マクロ内に表示される演算子ですawk
。keep-if
一般的な関数です。ここでは暗黙的にカレーなので、リスト引数は表示されません。述語関数が必要ですが、正規表現は関数呼び出し可能なので、述語として適しています。次に、以前に保存した最初のフィールドをフィールド
f
リストに戻します(push tmp f)
。(prn)
と同じですprint
。引数がない場合は、レコードとors
改行文字で初期化される出力レコード区切り文字()を印刷します。rec
のすべての操作が再構成されたため、フィルタリングされたf
出力を取得します。
ご覧のとおり、Awkパラダイムは基本的に完全です。他の言語の文脈で異なる種類のことが可能であるということです。フィールドが実際に存在することを確認せずに操作できる便利さは$2 > $1
ありませんが、フィールドをデータ構造として扱うためにループを作成する必要はありません。フィールドは関数を介してマッピングすることも、スタックとして表示することもできます。
SundeepのPerlソリューションは、おおよそawk
次のマクロに変換されます。
$ txr -e '(awk (t (prn `@[f 0]\t@{(keep-if #/cow|dog/ [f 1..:]) "\t"}`)))' data