回答:
ではawk
、フィールドセパレータを任意に設定できます。これをに設定するとC
、の出現と同じ数のフィールドに+1ができますC
。
だからあなたawk -F'C' '{print NF}' <<< "C1C2C3"
が得ると言うなら4
:CCC
は3 C
秒で構成されるため、4つのフィールドになります。
C
一度だけ発生する行を削除したい。これを考慮して、あなたのケースでは、ちょうど2つのC
フィールドがある行を削除する必要があります。だからそれらをスキップしてください:
$ awk -F'C' 'NF!=2' file
DTHGTY
HYTRHD
HTCCYD
awk 'BEGIN { print "FS={" FS"}","OFS={" OFS "}";} {printf "%d fields : ",NF; for (i=1;i<=NF;i++) {printf "{" $i "} ";}; print "" }'
いくつかの行を実行し、複数のspcesを含むものや、スペースで始まるものを実行してフィードすることができます)
sedアプローチ:
sed -i '/^[^C]*C[^C]*$/d' input
-i
オプションにより、ファイルのインプレース変更が可能
/^[^C]*C[^C]*$/
-1 C
回だけ含む行に一致します
d
-一致した行を削除
これは次のようにして行うことができますsed
:
コード:
sed '/C.*C/p;/C/d' file1
結果:
DTHGTY
HYTRHD
HTCCYD
どうやって?
C
viaのコピーを含む行を一致させて印刷する/C.*C/p
C
ビアのある行を削除します/C/d
。これには、手順1ですでに印刷された行が含まれます。これにより、Cが1つだけ出現する行が削除されます。
grep -v '^[^C]*C[^C]*$' file
正規表現[^C]
は、C(または改行)ではない1文字に一致し、繰り返し演算子(別名Kleeneスター)*
は、前の式の0回以上の繰り返しを指定します。
grep
(および他のほとんどのテキスト指向ツール)からのデフォルトの出力は、標準出力です。新しいファイルにリダイレクトし、必要に応じて元のファイルの上に移動することもできます。同じ正規表現sed -i
をインプレース編集に使用できます。
sed -i '/^[^C]*C[^C]*$/d' file
(一部のプラットフォーム、特にmacOSを含む* BSDでは、-i
オプションにはなどの引数が必要-i ''
です。)
sed -i '/^[^C]*C[^C]*$/d' file
-以前に投稿されたように聞こえますが、どのように考えますか、盗作?
grep
答えから始めましたが、明らかにsed -i
バリアントに簡単に拡張できます。以前のgrep
答えを探していたので、あなたの答えは見つかりませんでした。
-i
てsed
代わりに新しいファイルにリダイレクトし、元のファイルをそのファイルに置き換える方が安全sed
です。
grep -vx '[^C]*C[^C]*'
grep
より明確で堅牢であるため、使用することもできます(特に、sed
有益な終了コードが少ないため)。
ファイルのスクリプト編集用のPOSIXツールは(変更された内容を標準出力に出力するのではなく)ですex
。
printf '%s\n' 'g/^[^C]*C[^C]*$/d' x | ex file.txt
もちろん、Sedのバージョンがそれをサポートしている場合は使用sed -i
できますが、さまざまなタイプのシステムで実行することを目的としたスクリプトを作成している場合は移植できないことに注意してください。
David Foersterがコメントで尋ねました:
あなたが使っている理由はあり
printf
ませんecho
かex -c COMMAND
?
回答:はい。
とprintf
比較しecho
て、それは移植性の問題です。printfがechoよりも優れている理由を参照してください。 また、を使用してコマンド間に改行を挿入するのも簡単printf
です。
以下のためにprintf ... | ex
対ex -c ...
には、エラー処理の問題です。この特定のコマンドでは重要ではありませんが、通常は重要です。たとえば、入れてみてください
ex -c '%s/this pattern is not in the file/replacement text/g | x' filename
スクリプトで。次とは対照的です。
printf '%s\n' '%s/no matching lines/replacement/g' x | ex file
最初はハングし、入力を待ちます。2番目は、ex
コマンドがEOFを受信すると終了するため、スクリプトは続行されます。などの代替回避策s///e
がありますが、POSIXでは指定されていません。私は、上に示したポータブルフォームを使用することを好みます。
以下のためg
のコマンド、そこになければなりません最後に改行すること、そして私が使って好みprintf
のコマンドをラップするのではなく、単一引用符での改行を埋め込みます。
printf
ませんecho
かex -c COMMAND
?
printf
vs については知っていましたecho
(ただしecho
、引数がハードコーディングされている場合は、たいてい好んで使用ex
します)が、これまで広範囲に使用したことはありません。
ここでは、perlを使用するいくつかのオプションを示します。
一致するのは単一の文字だけなので、tr/C//
(置換なしの翻訳)を使用して、の一致数を返すことができますC
。
perl -lne 'print if tr/C// != 1' file
より一般的には、複数文字の文字列または正規表現に一致させたい場合は、これを使用できます。
perl -lne 'print if (@m = /C/g) != 1' file
これにより、正規表現の一致が/C/g
リストに割り当てられ、@m
そのリストの長さがでない場合に行が出力され1
ます。
-i
スイッチは「インプレース」編集に追加することができます。
sed -e '
s/C/&/2;t # when 2nd C matches skip processing and print
/C/d # either one C or no C, so delete on C
'
sed -e '
/C/!b # no C, skip processing and print
/C.*C/!d # not(at least 2 C) => 1 C => delete
'
perl -lne 's/C/C/g == 1 or print'
sed
、他のほとんどの実装でt #...
呼び出されるラベルに分岐します。#...
sed
b
、t
、:
、}
(とr file
、w file
...)同じ行にそれらの後にコマンドを持つことができません。別の-e
オプションを使用することもできます。
g
修飾子を追加するのを忘れたようです。
特に欲しい人のためにawk
、私は提供します
awk '/C[^C]*C/{next}//{print}'
パターンと一致する場合はその行をスキップし、そうでない場合は印刷します。実際には必要ありませんが{print}
、//
デフォルトの印刷を使用できますが、スペルがはっきりしていると思います。
私の最初の考えはegrep -v
同じパターンで使用することでしたが、それは実際に提起された質問に答えるものではありません。
{next}
ですか?言うだけでawk '/pattern/ {next} 1'
、パターンに一致しないすべての行が印刷されます。または、awk '!/pattern/'
それらを直接印刷することをお勧めします。
!/pattern/
(それはどういうわけか私の心を滑らせた)ですが、私はむしろ//{print}
不可解なものよりも自明であると思い1
ます。次の担当者がコードを保守する能力が最も低く、流暢であることを想定し、コードの効率や効果を大幅に低下させないようにします。
awk
フィールドセパレーターの使用を正確に!