最後にコメントされた行から「foo」のある行までのすべての行をコメントします


12

テキストファイルを考えますusers.txt

#alice
#bob
charlie
dotan
eric

最後のコメント行(包括的)から(包括的)までのすべてをコメントする必要がありdotanます。これが結果です:

#alice
#bob
#charlie
#dotan
eric

sedこれを行うための素敵なワンライナーはありますか?ただのツールだけsedでなく、本当に満足しています。

現在、最後にコメントされた行の行番号を取得しています:

$ cat -n users.txt | grep '#' | tail -n1
  2 #bob

私はそれを追加してコメントしsedます:

$ sed -i'' '3,/dotan/ s/^/#/' users.txt

私は賢く、これをいくつかと一緒にputいbcワンライナーにまとめることができることを知っています。確かにきれいな方法があるはずですか?

回答:


5

どう?

perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file

または、awkの同じ考え:

awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file

7

既存のコメント行が単一の連続したブロックを形成している場合、代わりに最初のコメント行から一致させ、コメントされていない終了パターンまでの行のみをコメントアウトすることができます

sed '/^#/,/dotan/ s/^[^#]/#&/' file

既存のコメントが連続していない場合、sed範囲一致の貪欲な性質のために、次のようなことをする必要があると思います

tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac

すなわち、終了パターンから「最初の」コメントまで上向きに一致します -もちろん、インプレースソリューションが必要な場合はそれほど便利ではありません。


4

1つのsed呼び出しで両方のケース(単一の連続したブロック内のコメント化された行、またはコメント化されていない行に散在している行)を処理できます。

sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile

これは、1,/PATTERN/範囲内の行のみを処理します。これは、E x変更がワットスペースを保持します。行がコメント化されるたびにパターンスペースがあり(したがって、ホールドバッファーにコメント化された行が複数存在することはありません)、H古いスペースにコメント化されていないすべての行を追加します(1行目で1d、それぞれ1h初期行を削除するためにも必要です)保留バッファの空行)。
PATTERNに一致する行に達すると、H古いバッファーにも追加され、e xがバッファーを変更して\nから、パターンスペース内のすべてのewline文字を\newlineおよびa #(つまり、パターンスペース内のすべての行が#、ホールドスペースの最初の行として最初の行を含めると、常にコメント行になります)。
サンプル付きinfile

alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry

ランニング:

sed '1,/dotan/{                   # if line is in this range    -start c1
/^#/{                             # if line is commented        -start c2
x                                 # exchage hold space w. pattern space
1d                                # if 1st line, delete pattern space
b                                 # branch to end of script
}                                 #                             -end c2
//!{                              # if line is not commented    -start c3
H                                 # append to hold space
/dotan/!{                         # if line doesn't match dotan -start c4
1h                                # if 1st line, overwrite hold space
d                                 # delete pattern space
}                                 #                             -end c4
//{                               # if line matches dotan       -start c5
x                                 # exchage hold space w. pattern space
s/\n/&#/g                         # add # after each newline character
}                                 #                             -end c5
}                                 #                             -end c3
}' infile                         #                             -end c1

出力:

alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry

以下からのみの行をコメント(および除く)のITはそれほど#charlieまでに(を含む)dotanとそのまま他の線を残します。
確かに、これは、行マッチングの前に常に少なくとも1行のコメント行があると想定していPATTERNます。そうでない場合は、交換前に追加のチェックを追加できます。/^#/{s/\n/&#/g}


ありがとう、私はこの答えから学ぶべきことがたくさんあります!
-dotancohen

ちょっと待ってください。これは最後の一連のコメント行ではありませんか?いいえ、わかりました、そうです。最後のシリーズ+ドータン。かなり気の利いた。
mikeserv

1
あなたは常に最高の質問を見つけます。ダムド・ドータンはしばらく私に投げられました-多分まだそうです、私はまだそれをテストしていません。ありがとう、ドン。
mikeserv

2

ここに別のものがありsedます:

sed  -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn'      \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et  -e\} -eP\;D <in >out

あなたが尋ねるとおりです。それは単にスタック上で動作します-必要に応じて、コメント行が発生する間、必要に応じてそれを構築し、入力が見つかったときに入力で新しいコメント行を優先して古いバッファをダンプします。画像...

ここに画像の説明を入力してください

申し訳ありませんが、なぜそうしたのかわかりません。しかし、それは思い浮かびました。

とにかく、sedすべてのシリーズの最後にコメントされた行の間にバッファーを広げ、最後にコメントされた発生を正確に追跡するために必要なよりも単一のバッファーをバッファに保持することはありません。最終的なgローブ実行ステートメントとブランチtは、バッファ全体を出力します。それ以外の場合はP、バッファから解放されるすべての行をリントします。

これがアコーディオンを思い起こさせたものだと思います...

printf %s\\n   \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric |
sed  -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn'     \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g'  \
-et  -e\} -eP\;D

#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric

このコマンドと上記のコマンドの違いは1つだけlです。これは上部のookコマンドです。動作するのパターンスペースにl注目sedすると、舞台裏で何が起こっているのか、その取り組みをどのように指示するかについての理解が深まります。

この場合、入力のsed2番目のオカレンスが見つかるまでスタック入力を監視\n#.*\ndotanし、それが前の出力を一度に1行ずつ出力し始めるまで監視できます。それはちょっとクールです。私はこれについて多くのことを学びました。


ありがとう、とても良いです!説明付きの最後の段落は素晴らしいです、私はこの投稿からもかなりの時間を学びます。素敵なスタック!
-dotancohen

1
@dotancohen-これは本当にいい質問でした。スタックを見るために編集を見てください
mikeserv

2
編集履歴でエントリに気付きHandle many dotansます。これは私の妻の最悪の悪夢だと確信しています。
-dotancohen

1
@dotancohen-ええ、これは大変でした。#\ndotan\ndotanこれらのことは好きです。これはいい質問だと言っています。私はそれをほぼ完璧に得たと思います、あなた遭遇する可能性のある問題の1つは、コメントブロックが1000行で区切られている場合です-それ遅くなります。たとえば、バッファが150行にまたがる場合s/\n/&/150;t、最初/\n#にバッファをブレークアウトする前に、次のようなものを貼り付けることができます。とにかく、多分それは彼女が待っているものばかりだすべてに沿って
mikeserv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.