次のファイルがありますswap
。
$ cat swap
aardvark BILL CLINTON dog
eternal CLINTON BILL forever
BILL good housekeeping BILL
BILL
toのすべての項目を変更し、toCLINTON
のすべての項目を同時に変更したいと思います。結果の出力は次のとおりです。CLINTON
BILL
aardvark CLINTON BILL dog
eternal BILL CLINTON forever
CLINTON good housekeeping CLINTON
私は古典的な解決策を知っています。
sed -e 's/BILL/temp/g' -e 's/CLINTON/BILL/g' -e 's/temp/CLINTON/g'
しかし、誰かが私に練習レベルで3番目の単語を使用しないように挑戦しました。
次のコマンドを使用していますが、最初の行でのみ機能します。
$ sed 's/\(BILL\) \(CLINTON\)/\2 \1/g' swap
aardvark CLINTON BILL dog
eternal CLINTON BILL forever
BILL good housekeeping BILL
注:私はSolaris 10オペレーティングシステムを使用しています。
この人為的な制約を観察しながら、どのような目的の出力を得ることができますか?
行動
MORBILLIFORM OVERBILLED
TOM, BILL, AND HARRISON
指定されていません。
答え1
perl -pe 's/(BILL)|CLINTON/$1 ? "CLINTON" : "BILL"/eg' swap
説明する:
-p
オプションを使用すると、Perl
ファイルlaがawk
1行ずつ読み取られ、すべての変換が適用された後に現在のレコードが自動的に印刷されます。
このs///
コマンドは現在の行で動作します。パターン/eg
修飾子は次のとおりです。/g
変換を最初の行に制限するのではなく、現在の行にグローバルに変換を適用します(記載されていない場合は)、変換をコードとして扱う/g
-uate/e
修飾子です。評価後の結果の値はRHSとみなされます。eval
RHS
s///
Perl
したがって、s/(BILL)|CLINTON/.../ は左からスキャンし、現在のレコードで BILL または CLINTON を検索します。 BILLが見つかると$1が設定されるので、Perl式$1 ? 「CLINTON」:「BILL」は、現在のレコードでBILLが置き換えられるCLINTONとして評価されます。しかし、修飾子のおかげで私たちは終わりました/g
。同様に、CLINTONが見つかった場合、$ 1は空であるため、Perl式$ 1? 「CLINTON」:「BILL」は、現在のレコードの終わりに達するまで、このレコードのCLINTONであるBILLとして評価されます-p
。 STDOUTとして印刷されます。
sed -e 's/BILL\|CLINTON/\n&/g;s/\nBILL/CLINTON/g;s/\nCLINTON/BILL/g' swap
答え2
アッ解決策:
awk '{ for(i=1;i<=NF;i++) { if($i=="BILL") $i="CLINTON"; else if($i=="CLINTON") $i="BILL" } }1' swap
出力:
CLINTON BILL
BILL CLINTON
CLINTON CLINTON
for(i=1;i<=NF;i++)
- すべてのフィールドに対して繰り返し(アッスペースをデフォルトフィールド区切り文字として扱う)if($i=="BILL") $i="CLINTON"
- フィールド値が等しい場合BILL
- 割り当てCLINTON
else if($i=="CLINTON") $i="BILL"
- それ以外の場合、フィールド値が同じ場合CLINTON
- これを次に割り当てます。BILL
答え3
別のawkソリューション
awk '{
while (match($0, /BILL|CLINTON/)) {
printf "%s", substr($0, 1, RSTART-1);
$0 = substr($0, RSTART);
printf "%s", /^BILL/ ? "CLINTON" : "BILL";
$0 = substr($0, 1+RLENGTH)
}
print
}' swap