從文件中刪除評論,同時忽略引用的評論標誌
我想
#
從文件中刪除以開頭的評論。我嘗試瞭如何從文件中刪除所有註釋中描述的更簡單的方法?但我還有一些額外的規則:
- 如果註釋作為引用字元串的一部分出現,則A
#
不會開始註釋。- 字元串可以用單引號
'
或雙引號引起來"
。- 如果前面有反斜杠,雙引號字元串可以包含引號
\"
,反斜杠引用為\\
.- 輸入中的所有引號都匹配。但是,對於作為字元串內容一部分的引號(換句話說
"'"
,"\""
並且'"'
是有效字元串),這不是必需的。- 帶引號的字元串不能包含換行符。
- 註釋可以包含任何字元,包括任意數量的
#
、和。'``"``\
- 引號之外的任何內容都會
#
開始註釋(正如Stéphane Chazelas指出的大多數 shell 的程式碼程式碼遵循更複雜的規則 - 想想$#
不開始註釋的 Bash)。例如以下輸入
# comment only # comments are allowed to contain quotes "' and # number signs # comments are allowed to contain pairs 'of' "quotes" some text # with an explanation some "quoted text # not a comment" # comment '# not a comment' and '# not a comment either' # comment "# not a comment containing 'quotes\"" # another comment
應轉換為以下輸出
some text some "quoted text # not a comment" '# not a comment' and '# not a comment either' "# not a comment containing 'quotes\""
我想在現代 Debian/Ubuntu 系統上
awk
使用流行grep
的Unix 命令行工具來完成此任務。sed
我並不嚴格限制於 POSIX 描述的功能,但最好使用符合 POSIX 的解決方案。
如果重點是從 POSIX sh 腳本中刪除註釋,請注意,只有在下面的程式碼中標記為 YES 的才是註釋:
echo 1 # YES echo 2 $# NO foo# NO echo 3;#YES # YES cat << E # NO E echo 4 " # NO \" # NO" \" # YES echo "5 # NO $(echo 6 # YES ) `echo 7 \" # NO \"` " eval 'echo 8 # NO, then YES'
(您可以看到 stackexchange 語法高亮顯示在大多數情況下都會出錯)。
awk
覆蓋這些需要數百行sed
程式碼。
csh
,fish
,perl
,python
的規則ruby
是其他語言有"..."
和'...'
引用並#
作為評論領導者將完全不同。如果
- 這與 shell 語法無關,
- 您可以假設沒有轉義引號,
- 引用的字元串不包含換行符,
- 所有引號都匹配,
- 引號之外的任何內容都會
#
開始註釋,而不僅僅是空格或其他分隔符之後的註釋,- 輸入是目前語言環境中的有效文本
如果按照標準您是指 POSIX 2018 或更早版本,您可以
sed
使用:sed "s/^\(\(\([^\"'#]\)*\(\"[^\"]*\"\)\{0,1\}\('[^']*'\)\{0,1\}\)*\)#.*/\1/"
POSIX 2018
sed
不支持-E
交替運算符所需的 ERE,但在這裡我們通過\(a\{0,1\}b\{0,1\}\)*
((a?b?)*
在 ERE 中)作為(a|b)*
. 在Rakesh 的回答中使用(a*b*)*
as也可以。
grep
不會是一個選項,因為標準grep
只列印完整的匹配行。awk
雖然使用 ERE。標準 awk 沒有擷取組,但您應該能夠執行以下操作:awk "match(\$0, /^([^'\"#]|\"[^\"]*\"|'[^']*')*#/) { \$0 = substr(\$0, 1, RLENGTH-1) } {print}"
根據您編輯的要求,您可以使用
"(\\.|[^\\"])*"
或其 BRE 等效項來處理轉義的引號:sed 's/^\(\(\([^"\\'\''#]\)*\(\\.\)\{0,1\}\("\([^"\\]*\(\\.\)\{0,1\}\)*"\)\{0,1\}\('"'[^']*'\)\{0,1\}\)*\)#.*/\1/"
或者:
awk 'match($0, /^([^'\''"\\#]|\\.|"(\\.|[^\\"])*"|'\''(\\.|[^\\'\''])*'\'')*#/) { $0 = substr($0, 1, RLENGTH-1) } {print}'
兩者都處理引號之外的轉義引號(如
foo\"bar # comment
)。我這裡改用單引號來減少獲取文字需要插入的反斜杠的數量
\\
,但是數據中的文字單引號必須插入為'before'\''after'
,即'\''
首先'
關閉帶'before'
引號的字元串,\'
使用反斜杠引用/轉義文字'
(因為您不能在單引號字元串中插入單引號),然後'after'
引用字元串。