1.5MBファイルがあります。
1行には約160,000文字があります。
この行では、PATTERNの直後に「false」を「true」に一度変更するだけです。
awkの後、最初の発生のみが変更されます。
ただし、「PATTERN」以降は一度だけ変更してください。
awk '/PATTERN.*false/ {sub("false", "true")} {print}' file
私たちのファイルは次のとおりです。
...
colorA is false colorB is false PATTERN is false colorC is false colorD is false
...
ファイルには以下が必要です。
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...
必要に応じてawkコマンドをどのように配置しますか?
よろしくお願いします!
答え1
「false」と一致しない最短文字列に一致する正規表現を作成することは理論的に可能ですが、難しいです。他のさまざまな言語にはselect-shortest構文がありますが、awkはそのうちの1つではありません。
したがって、難しい表現を作成したくないと仮定すると、3つのアプローチがあります。
- 入力を「false」という単語に分割し、フィールドを繰り返して、現在のフィールドがパターンと一致する場合は「true」の後に印刷し、それ以外の場合は「false」の後に印刷できます。
- トリックを使用して、「false」のすべての項目をcontrol-aなどの未使用の単一文字に変換できます。これにより、正規表現は、最も短いモード制御で終わるものと一致するように[^\001]*\001と言えるように書くのは簡単です。 -ㅏ。
- フィールドを繰り返し、現在のフィールドがスキーマの場合はフラグを設定し、「false」、フラグが設定されている場合は「true」に変更し、フラグをリセットします。
方法3の場合。
#!/usr/bin/awk
/PATTERN.*false/ {
for(i=1;i<=NF;i++) {
if ($i ~ /PATTERN/) flag=1;
if ($i == "false" && flag==1) {
$i="true"
flag=0
}
}
}
{print}
これにより、入力の空白が縮小されます。
答え2
PATTERN
解決策は()で行分割を実装しsplit
、最初の部分をfalse
2番目の部分()で置き換え、その部分を結合します(ループ合計)。このコマンドはこの入力ラインの追加処理をスキップします。他の行は変更されずに印刷されます。 (デフォルトの動作がある場合は常に真の条件です。)sub
for
printf
next
1
awk '/PATTERN.*false/ {
n=split($0,parts,"PATTERN");
sub("false", "true", parts[2]);
for(i=1;i<n;i++) {
printf("%s%s", parts[i], "PATTERN");
}
printf("%s\n", parts[n]);
next }
1'
PATTERN
その値が常に存在するかどうかは質問で明確ではないため、代替エラーになる可能性false
がありますfalse
。
入力サンプル
colorA is false colorB is false PATTERN is false colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false
結果は次のとおりです。
colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is true colorD is false
編集する~によるとルーディック注:PATTERN以降に変更される値が「true」または「false」の場合、ディレクティブを次のように置き換えることでこのsub("false", "true", parts[2]);
問題を回避できます。sub("false|true", "true", parts[2]);
awk '/PATTERN.*false/ {
n=split($0,parts,"PATTERN");
sub("false|true", "true", parts[2]);
for(i=1;i<n;i++) {
printf("%s%s", parts[i], "PATTERN");
}
printf("%s\n", parts[n]);
next }
1'
同じサンプル入力を使用すると、結果は次のようになります。
colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false
答え3
GNU awkを使用してmatch()とgensub()に3番目の引数を渡します。
$ awk 'match($0,/(.*PATTERN)(.*)/,a){$0=a[1] gensub(/false/,"true",1,a[2])} 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...
そしていくつかの奇妙な:
$ awk 'match($0,/.*PATTERN/){tail=substr($0,RSTART+RLENGTH); sub(/false/,"true",tail); $0=substr($0,1,RSTART+RLENGTH-1) tail } 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...