文字列内にある「#」に関して、ファイル(#で定義)からsedを使用してすべてのコメントを削除するにはどうすればよいですか?
これは、弦の部分を除いて非常に役立ちました。
常にコメントを意味し、行のどこにでも表示できる場合#
(コードの後など):
sed 's:#.*$::g' <file-name>
所定の位置に変更する場合は、-i
スイッチを追加します。
sed -i 's:#.*$::g' <file-name>
#
これにより、コンテキストを無視して、行の末尾までが削除されます。#
コメントではない場所(文字列など)で使用すると、コメントも削除されます。
コメントが行の先頭からしか開始できない場合は、次のようにします。
sed 's:^#.*$::g' <file-name>
それらの前に空白が付いている可能性があるが、他に何もない場合は、次のようにします。
sed 's:^\s*#.*$::g' <file-name>
#
これらの2つは、文字列などのコードでの有効な使用法を削除しない可能性があるため、少し安全になります。
編集:
文字列に何かが含まれているかどうかを検出する良い方法はありません。それがあなたの言語の制約を満たすなら、私は最後の2つを使います。
文字列内にあるかどうかを検出する際の問題は、正規表現ではすべてを実行できないことです。いくつかの問題があります:
正規表現はネストされた引用符と一致できません(これらの場合は正規表現を混乱させます):
# "hello there"
# hello there"
"# hello there"
文字列を定義する唯一の方法が二重引用符である場合、二重引用符がコメントに表示されることはなく、文字列が複数行にまたがることはできません。次のようにしてみてください。
sed 's:#[^"]*$::g' <file-name>
それは多くの前提条件ですが、それらがすべて成立する場合、あなたはビジネスに従事しています。そうでなければ、あなたはSOLだと思います。より高度なロジックを実行できる、Pythonのようなもので記述したほうがよいでしょう。
これはうまくいくかもしれません(GNU sed):
sed '/#/!b;s/^/\n/;ta;:a;s/\n$//;t;s/\n\(\("[^"]*"\)\|\('\''[^'\'']*'\''\)\)/\1\n/;ta;s/\n\([^#]\)/\1\n/;ta;s/\n.*//' file
/#/!b
#
ラインにベイルアウトが含まれていない場合s/^/\n/
一意のマーカーを挿入する ( \n
)ta;:a
ループ ラベルにジャンプします (代替の true/false フラグをリセットします)s/\n$//;t
ラインの最後にマーカーがある場合は、削除して救済しますs/\n\(\("[^"]*"\)\|\('\''[^'\'']*'\''\)\)/\1\n/;ta
マーカーに続く文字列が引用符で囲まれたものである場合、マーカーを前方にぶつけてループします。s/\n\([^#]\)/\1\n/;ta
マーカーに続く文字が でない場合は#
、マーカーを前方にぶつけてループします。s/\n.*//
行の残りはコメントです。マーカーと行の残りを削除します。asker からサンプル入力が提供されていないため、いくつかのケースを想定します。質問のタグとして bash が使用されているため、入力ファイルは Bash です。
ケース 1 : 行全体がコメント
ほとんどの場合、以下で十分です。
sed '/^\s*#/d' file
これは、先行する空白文字 (スペース、タブ、またはその他のいくつかの文字、「 」を参照man isspace
) がまったくないか、少なくとも 1 つ含まれ、#
その後に が続く任意の行に一致し、コマンドでその行を削除しd
ます。
次のような行:
# comment started from beginning.
# any number of white-space character before
# or 'quote' in "here"
それらは削除されます。
しかし
a="foobar in #comment"
これは望ましい結果です。
ケース 2 : 実際のコードの後にコメント
例えば:
if [[ $foo == "#bar" ]]; then # comment here
コメント部分は次の方法で削除できます
sed "s/\s*#*[^\"']*$//" file
[^\"']
引用符付き文字列の混乱を防ぐために使用されますが、引用符付きのコメント'
または"
削除されないことも意味します。
最終シード
sed "/^\s*#/d;s/\s*#[^\"']*$//" file
「文字列内にある」とは、「一重引用符または二重引用符のペアの間に発生する」という意味であるとすると、質問は「最初の引用符で囲まれていない#の後のすべてを削除する」と言い換えることができます。引用符で囲まれた文字列は、バックスラッシュされた引用符を除いて、2つの引用符の間の任意のものとして定義できます。マイナーな改良として、最初の引用符で囲まれていない#の直前までのすべての行を置き換えます。
したがって[^\"'#]
、些細な場合のようなものが得られます。コメント記号でも、バックスラッシュでも、開始引用符でもない文字列です。次に、バックスラッシュの後に何かを受け入れることができます。-これ\\.
は文字通りのドットではなく、文字通りのバックスラッシュであり、その後に任意の文字に一致するドットメタ文字が続きます。
次に、引用符で囲まれた文字列の0回以上の繰り返しを許可できます。一重引用符または二重引用符を受け入れるには、それぞれを0個以上許可します。引用符で囲まれた文字列は、開始引用符の後に、バックスラッシュされた任意の文字、または終了引用符を除く任意の文字の0個以上が続くものとして定義さ"\(\\.\|[^\"]\)*"
れます'\(\\.\|[^\']\)*'
。
これらすべてをつなぎ合わせると、sed
スクリプトは次のようになります。
s/^\([^\"'#]*\|\\.\|"\(\\.\|[^\"]\)*"\|'\(\\.\|[^\']\)*'\)*\)#.*/\1/
ただし、引用符で囲む必要があり、文字列には一重引用符と二重引用符の両方が含まれているため、もう1つ複雑にする必要があります。シェルを使用すると、二重引用符と一重引用符で-に"foo"'bar'
置き換えられるように文字列を接着できることを思い出してください。したがって、一重引用符で囲まれた文字列に隣接する二重引用符で囲むことにより、一重引用符を含めることができます。に隣接していると表現できます。したがって、両方の二重引用符を含む一重引用符で囲まれた文字列は、隣接して引用することができます。この場合、より現実的には隣接して引用することができます。foobar
foo
bar
'"foo"'"'"
"foo"
'
"foo"'
"'
'"'
"'"
foo"'bar
'foo"'
"'bar"
'foo"'
"'"
別の一重引用符で囲まれた文字列'bar'
に隣接して、を生成し'foo'"'"'bar'
ます。
sed 's/^\(\(\\.\|[^\#"'"'"']*\|"\(\\.\|[^\"]\)*"\|'"'"'\(\\.\|[^\'"'"']\)*'"'"'\)*\)#.*/\1/p' file
これはLinuxでテストされました。他のプラットフォームでは、sed
方言が少し異なる場合があります。たとえば、グループ化および変更演算子の前に円記号を省略する必要がある場合があります。
残念ながら、複数行の引用符で囲まれた文字列がある場合、これは機能しません。sed
、設計上、一度に1つの入力行のみを調べます。複数の行をメモリに収集する複雑なスクリプトを作成することもできますが、それまでに、たとえばPerlに切り替えることは非常に理にかなっています。
sed 's:^#\(.*\)$:\1:g' filename
行が単一の # コメントで始まると仮定すると、上記のコマンドはファイルからすべてのコメントを削除します。