現在、私のファイルには次のセクションが含まれています。
code statement1
code statement2
# BEGIN SOMENAME
some code
some other code
# END SOMENAME
code statement n +1
code statement n +1
私がしたいのは、間の内容をコメントアウトすることです。
# BEGIN SOMENAME
そして
# END
だから結局、次のように見えます。
code statement1
code statement2
# BEGIN SOMENAME
# some code
# some other code
# END SOMENAME
code statement n +1
code statement n +1
awk
またはを使用してこれを達成できますかsed
?もう一度「コメントする」だけで簡単に元に戻せますか?
私が避けたいのは間違いです。したがって、この行がすでにコメント化されている場合はそのままにしてください。また、「コメント入力」でendとstartの間の行がで始まらない限り、何かを試してはいけません#
。
考えられる解決策が見つかりました。
awk '
BEGIN {
i=0;
line_with_no_comment_found=0
}
/^# END/ {
m=0;
if ( line_with_no_comment_found == 1 ) {
for (var in a) print "# "a[var]
} else {
for (var in a) print a[var]
}
delete a;
i=0;
line_with_no_comment_found=0;
}
/^# / {
if (m==0) {
print
} else {
a[i++]=$0;
}
}
!/^# / {
if (m==0) {
print
} else {
a[i++]=$0;
line_with_no_comment_found=1
}
}
/^# BEGIN ([a-zA-Z_])([1-9][0-9]*)*/ {
m=1;
}
END { }
'<<EOF
答え1
このスクリプトは私にとって効果的です。私はこれをGNU Awk 4.0.1でテストしましたが、Nawkでも動作します。
awk 'BEGIN {
# action=0: uncomment
# action=1: comment
action=0
in_optional_code_block=0
}
{
if ($0 ~ /^# BEGIN/) {
in_optional_code_block=1
} else if ($0 ~ /^# END/) {
in_optional_code_block=0
} else if (in_optional_code_block) {
if (action) {
if ($0 !~ /^#/) {
$0 = "# " $0
}
} else {
if ($0 ~ /^#/) {
sub(/^# ?/, "")
}
}
}
}
1'
私もそれに付属の小さなシェルスクリプトを書いています:
#!/usr/bin/env sh
syntax_error() {
echo "Usage: `basename \"$0\"` [comment|uncomment] file" >&2
exit 1
}
case "$1" in
0|uncomment) action=0; ;;
1|comment) action=1; ;;
*) syntax_error; ;;
esac
shift
if [ -z "$@" ]; then syntax_error; fi
awk 'BEGIN {
action='$action'
in_optional_code_block=0
}
{
if ($0 ~ /^# BEGIN/) {
in_optional_code_block=1
} else if ($0 ~ /^# END/) {
in_optional_code_block=0
} else if (in_optional_code_block) {
if (action) {
if ($0 !~ /^#/) {
$0 = "# " $0
}
} else {
if ($0 ~ /^#/) {
sub(/^# ?/, "")
}
}
}
}
1' "$@" > "[email protected]"
if [ $? -eq 0 ]; then mv "[email protected]" "$@"; fi
(GNU Awk 4.1.0以降では、構造体を移動するのではなく、最後に-iフラグを使用できます。)
答え2
質問の「可能な解決策」を解決すると、提案されたコードにはいくつかの問題があります。
- ループは
for (var in a)
インデックスを順番に繰り返すことは保証されていないため、コメントアウトされた行はa
ランダムな順序で潜在的に出力される可能性があります。 BEGIN
合計行を検出するために使用するパターンは、2行END
で使用されているラベルをペアで連結しようとしないため、で終わることがあり# BEGIN FOO
ます# END BAR
。/^# /
ブロック間に不要なコードの重複があります!/^# /
。- 空のブロックが
END
不必要に存在します。 - コードのコメントは解除されませんでした。
注釈の影響を受けるセクションで、コメントアウトされた行のコメントアウトを簡単に無効にするために、開くと閉じるバー#
に追加の文字も追加しました。
sed '/^# BEGIN SOMENAME$/,/^# END SOMENAME$/ s/^/#/' file
これにより、#
対応するバーを含む行と行の間のすべての行の先頭に文字が挿入されます。# BEGIN SOMENAME
# END SOMENAME
特定のテキストに対して、次の結果が発生します。
code statement1
code statement2
## BEGIN SOMENAME
#some code
#some other code
## END SOMENAME
code statement n +1
code statement n +1
その文字がまだ最初の文字ではない行にのみ挿入されている場合、表示された行#
の間に元の推奨行の記録がないため、反転操作は非常に困難です。
コメントを解除するには:
sed '/^## BEGIN SOMENAME$/,/^## END SOMENAME$/ s/#//' file
これは最初のコマンドで推奨される行にのみ影響し、各行sed
の先頭に挿入された文字を削除して元の状態に戻します。#
#
空白文字とそれに続く文字を使用して行をコメントアウトしたいと思います。
sed '/^# BEGIN SOMENAME$/,/^# END SOMENAME$/ s/^/# /' file
コメントを投稿するには
sed '/^# # BEGIN SOMENAME$/,/^# # END SOMENAME$/ s/# //' file
コメントをキャンセルするために使用されます。
awk
代わりに同等の操作を使用してくださいsed
。
コメント:
awk '$0 == "# BEGIN SOMENAME", $0 == "# END SOMENAME" { $0 = "#" $0 }; 1' file
コメントをキャンセルするには:
awk '$0 == "## BEGIN SOMENAME", $0 == "## END SOMENAME" { $0 = substr($0, 2) }; 1' file
どちらのコマンドも正規表現の代わりに文字列比較を使用します。なぜなら、正規表現は通常より速く、パターンマッチングを必要としないからです。コメント解除のための2番目のコマンド呼び出しは、substr()
入力文字列から最初の文字を引いた値を返します。後行だけで1
現在行が出力されます。