改行で区切られた複数の段落の1つのコメントを削除するにはどうすればよいですか?

改行で区切られた複数の段落の1つのコメントを削除するにはどうすればよいですか?

説明:GNU sedを使用してください。

現状 - ~/.screenrc、最後の数行:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

# name thrashmetal
# screen -t script emacs -nw /home/$USER/bin/thrashmetal
# number 1
# split -v
# focus
# chdir "/home/$USER/thrashmetal/src"
# screen -t scr watch nl asdkjlek.html
# number 2
# focus
# split
# focus
# screen -t output watch thrashmetal asdkjlek.html
# number 3
# focus
# split
# focus
# chdir "/home/$USER/thrashmetal/plan"
# screen -t soll watch less soll
# number 4
# focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

目的:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

現在の試みはほとんど成功しましたが、次の行が表示されたら停止しません。この行は、コメント記号や英数字のない新しい行です。

sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc

説明、意図:

  • '一連のやるべきことの始まり

  • s変える

  • +「+」を区切り文字として使用してください。

  • # …「#」で始まる行が見つかるまで1行ずつ見てください。

  • \(後で参照できるようにグループを開始

  • name thrashmetalそして「スラッシュメタル名」で続けてください。

  • \)グループの終わり

  • +\1+行の最初の項目を「#」なしでグループ部分に置き換えます。

  • ;そしてその時点から別のことをしてください...

  • :a「a」というループを作ります。

  • ;s各後続の行ごとに1行ずつ交換してください。

  • +「+」を区切り記号に設定

  • #行の後に続く内容に関係なく、行に「#」が最初に表示される場合...

  • ++何もありません。効果的に削除してください。

  • ;ta失敗したら、段落の終わりに達すると、スラッシュメタルブロックとダークウェーブブロックを区切る2行が壊れます。、次に「a」の位置に戻ります。

  • '一連のやり方が終わりました。

  • .screenrc現在のディレクトリ(マイホームディレクトリ)にある「.screenrc」ファイルに対して一連の操作を実行します。

標準出力:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

name darkwave
screen -t script emacs -nw /home/$USER/bin/darkwave

この問題を解決するには?スラッシュメタル段落の終わりに達するとすぐにループが止まらず、単に次の段落(darkwave段落)にジャンプして続くようにするには、私が何を間違っているのでしょうか?

私の考えでは、そのループにあるものは何でも間違っていると思います...おそらく「t」かもしれませんが、「T」や「b」も切り捨てられません...

答え1

sed '/^# name thrashmetal$/,/^$/ s/^# //' file

#これにより、範囲内の各行から最初と後続の空白文字が削除され、置換が適用されます。

範囲は行一致で始まり^# name thrashmetal$、最初の後続の行一致^$(空行)で終わります。

または次に直接翻訳されますawk

awk '/^# name thrashmetal$/,/^$/ { sub(/^# /, "") }; 1' file

ここで、末尾は、1または{ print $0 }の省略形{ print }として現在の(修正可能な)行が出力されるようにします(テキスト印刷はsedスクリプトに暗黙的に適用されます)。


編集者に興味がある人は、ed次の編集コマンドを使用してこの問題を解決できます。

/^# name thrashmetal$/;.,/^$/ s/^# //

これにより、カーソルが目的の段落の最初の行に移動し、空の行に達するまで、その行とすべての後続の行に代替が適用されます。

私たちは使用できません

/^# name thrashmetal$/,/^$/ s/^# //

...アドレスは現在の行に基づいて計算され、現在の行はエディタの起動時にファイルの末尾にあるためです。ファイルの末尾にあるため、アドレスが/^$/開始アドレスよりも前の行になるため、コマンドの範囲は何の影響もありません。 (最初の空白行は現在の行に基づいて段落の先頭の前にあります。)


独自の方法が修正されました(区切り記号をプラス記号からデフォルト値に変更し、複数の式に分割することで移植性が高くなります)。

sed -e '/^# \(name thrashmetal\)/!b' -e 's//\1/' -e :a -e n -e 's/^# //' -e ta file

最初の置換を実行する代わりに、段落の最初の行の一致によって、残りの編集スクリプトをスキップするかどうかが決まります。bその行が見つからない場合はスキップします。

行が見つかったら、それを修正してラベルを作成しますa。次に現在のバッファを印刷し、その内容を次の行に置き換えますn。ループは以前と同様に続き、#バッファの内容が変更されると部分文字列を削除してラベルにループし直します。

最初の試みの主な問題は次のとおりです。

sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc

... " a-loop"は無条件であるため、最初の置換が成功したかどうかに関係なく、入力されたすべての行に適用されます(最初の2行はコマンドの影響を受けませんが、コピー/貼り付けエラーのようです)。 。ループは次の行も読みませんので、単に実行されます。一度1行あたり(#1行に複数の部分文字列が見つからない限り)

私の修正は、最初の交換をテストと交換に分割し、交換がa失敗するまで「-loop」が入力の次の行を読み取ることを確認することでした。また、どの行でも複数の文字列や埋め込み(内部)文字列を変更せずに、行の先頭の#最初の文字列のみを置き換えました。

答え2

このスクリプトはあなたが望むことをするようです。

H
/^$/ T show
$ T show
d

:show
x
s/\n//
/^# name thrashmetal/ {
  s/# //
  s/\n# /\n/g
}

私たちは効果的に空白の線で区切られた塊に物を分割します。で始まるブロックが見つかったら、lineで始まるすべての文字列を# name thrashmetal削除します#

入力例が与えられると、出力が生成されます。

$ sed -f filter.sed < example.conf
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

コメント付きの sed スクリプト:

# Append current line to the hold space
H

# If we find a blank line or reach EOF, print out the
# current chunk
/^$/ T show
$ T show

# Delete the current line (we'll print it later in the
# show routine)
d

:show
# Swap the pattern space and the hold space
x

# Remove the initial "\n" that was added when we appended
# the first line with the H command
s/\n//

# If this is our target chunk, remove the comments
/^# name thrashmetal/ {
  s/# //
  s/\n# /\n/g
}

答え3

awkの使用を検討することもできます。

$ awk -v RS= -v ORS='\n\n' '/thrashmetal/{sub(/^# /,"");gsub(/\n# /,"\n",$0)}1'  .screenrc
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop 

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus 

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave 

ここで、RS(Input Record Separator)を空白に設定することで、段落を単一行として扱うことができます。

答え4

使用幸せ(以前のPerl_6)

~$ raku -ne 'if / thrashmetal /fff^/ \# \s name / { .subst(/^ "\# " /).put } else { $_.put };'  file

または:

~$ raku -ne 'put (/ thrashmetal /fff^/ \# \s name /) ?? $_.subst(/^ "\# " /)  !! $_ ;'  file

RakuはPerlファミリーのプログラミング言語です。 Raku-neのawkに似た非自動印刷コマンドラインフラグとif / elseステートメントを使用して、選択した行を変更できます。

ここで重要なのは、/…ON…/fffˆ/…OFF…/最初の認識フィールドが一致するとONに変わり、2番目の認識フィールドが一致するとOFFに変わるRakuの「トリガー」演算子を使用することです。これに基づいて、fffここに末尾の^キャレットを追加して、Rakuに2番目の一致行を削除するように指示します。

thrashmetalしたがって、最初の一致と\# \s name2番目の一致の両方に必要なコメント付きレコード/段落を一度に一致させることができます。識別されたレコードのコメント解除を使用してください.subst(/^ "\# " /)

入力例:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

# name thrashmetal
# screen -t script emacs -nw /home/$USER/bin/thrashmetal
# number 1
# split -v
# focus
# chdir "/home/$USER/thrashmetal/src"
# screen -t scr watch nl asdkjlek.html
# number 2
# focus
# split
# focus
# screen -t output watch thrashmetal asdkjlek.html
# number 3
# focus
# split
# focus
# chdir "/home/$USER/thrashmetal/plan"
# screen -t soll watch less soll
# number 4
# focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

出力例:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

https://docs.raku.org/routine/fff%5E
https://raku.org

関連情報