2012-11-25 51 views
7

如何从文件(使用#定义)中删除关于字符串中的#的所有注释?使用sed删除文件中的所有注释

This帮助了很多,除了字符串部分。

+1

能#之前的开始出现在任何上下文评论? – FoolishSeth

+1

字符串是如何定义的?字符串(如引号)是否会出现在评论中? – tjameson

+1

如果你正在讨论shell脚本中的注释,你需要担心的不仅仅是字符串。例如,在'echo foo#bar'或'echo $ {foo#bar} $ {foo ## bar}'中没有评论。 –

回答

10

如果#总是意味着评论,可以在一行出现在任何地方(比如一些代码后):

sed 's:#.*$::g' <file-name> 

如果你想改变它在的地方,添加-i开关:

sed -i 's:#.*$::g' <file-name> 

这将从任何#删除到行末,忽略任何上下文。如果你在任何不是注释的地方使用#(比如在字符串中),它也会删除它。

如果注释可以在一行的开头只是开始,做这样的事情:

sed 's:^#.*$::g' <file-name> 

如果他们可以用空白开头,但没有别的,这样做:

sed 's:^\s*#.*$::g' <file-name> 

这些两个会更安全一些,因为它们可能不会删除代码中的有效使用#,例如在字符串中。

编辑:

有检测的东西是否是在一个字符串一个很好的方式不是真的。如果能满足您的语言限制,我会使用最后两个。

检测您是否在字符串中的问题是正则表达式不能做所有事情。有几个问题:

  • 字符串可能可以跨行
  • 正则表达式不能告诉apostrophies和单引号
  • 之间的差异
  • 正则表达式无法比拟的嵌套引号(这些案件会混淆正则表达式):

    # "hello there" 
    # hello there" 
    "# hello there" 
    

如果双引号是字符串中定义的唯一途径,双引号将永远不会出现在发表评论,字符串不能跨越多行,尝试这样的:

sed 's:#[^"]*$::g' <file-name> 

这是一个很大的先决条件,但如果他们都持有,你在企业里。否则,我担心你是SOL,并且最好将它写入Python之类的东西,在那里你可以做更多的高级逻辑。

+0

'的sed的:#[^“] * $ :: G''错误地在'的sed的/ \ */\ */g'' – locke

+0

需要的空间之前,#是''#后除去一切一个好主意:做两步,以#开始的行和包含(空格#)的行如下:'sed -e's/^ [\ t] *#[^!]。* $ // g'-e这会避免大多数脚本用于#:'echo“$ {#a} $#$ {a#3} $((16#11) )“'' 是 – 2015-06-17 09:06:42

+0

的'g'标志需要它不像文本行会的行多个终端 – Sukima

3

由于asker没有提供样本输入,所以我将假设几个例子,Bash是输入文件,因为bash被用作问题的标签。

案例1:整行是注释

下应足以在大多数情况下:

sed '/^\s*#/d' file 

它匹配任何一行都有已经没有或至少一个领先涂白空格字符(空格,制表符或其他几个字符,请参阅man isspace),然后是#,然后通过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系列的最后

sed "/^\s*#/d;s/\s*#[^\"']*$//" file 
+0

没有,这是专门为失败的问题陈述的soecific问题;?即,它不不要留下带引号的字符串 – tripleee

+0

然后请提供这些*引号字符串的示例代码*。 – livibetter

+0

或者最好的,一个完整的文件来测试预期的输出结果我们不是通灵者,我们不能猜测。 Ÿ答案,它处理引用的字符串。 – livibetter

5

这可能为你工作(GNU SED):

sed '/#/!b;s/^/\n/;ta;:a;s/\n$//;t;s/\n\(\("[^"]*"\)\|\('\''[^'\'']*'\''\)\)/\1\n/;ta;s/\n\([^#]\)/\1\n/;ta;s/\n.*//' file 
  • ​​如果该行不包含#保释出来
  • s/^/\n/插入一个独特的标记(\n
  • ta;:a跳跃到一个循环的标签(复位替代真/假标志)
  • s/\n$//;t如果标记在该行的末端,取出并拯救
  • s/\n\(\("[^"]*"\)\|\('\''[^'\'']*'\''\)\)/\1\n/;ta如果标记后的字符串是引用一个,将标记向前碰撞并循环。
  • s/\n\([^#]\)/\1\n/;ta如果标记后面的字符不是#,则将标记向前碰撞并循环。
  • s/\n.*//该行的其余部分是注释,删除标记和行的其余部分。
+0

这是否会在HERE文档中替换注释? – rubo77

1

假设“在一个字符为”是指,这个问题可以被改述为“一对引号,无论是单或双的之间发生”,“第一无引号#后除去一切”。您可以将引用的字符串依次定义为两个引号之间的任何内容,除了反斜杠之外的引号。作为一个细微的改进,在第一个未加引号的#之前,将所有行全部替换。

所以我们得到像[^\"'#]这样的小事例 - 一段既不是注释符号也不是反斜线,也不是开头引号的字符串。然后我们可以接受任何反斜线:\\. - 这不是一个字面点,这是一个文字反斜杠,后面跟着一个与任何字符匹配的点元字符。

然后,我们可以允许零个或多个重复的引用字符串。为了接受单引号或双引号,请允许每个引用中的零个或多个引号。带引号的字符串应定义为开头引号,后面跟零或多个任意一个反斜线的任意字符或除结尾引号外的任何字符:"\(\\.\|[^\"]\)*"或类似的单引号字符串'\(\\.\|[^\']\)*'

凑合这一切在一起,你sed脚本可能是这个样子:

s/^\([^\"'#]*\|\\.\|"\(\\.\|[^\"]\)*"\|'\(\\.\|[^\']\)*'\)*\)#.*/\1/ 

但由于它需要被引用,和单,双引号包含在字符串中,我们需要一个更额外的并发症。回想一下,shell允许你把"foo"'bar'这样的字符串粘在一起,用双引号替换为foobar - foo,用单引号替换bar。因此,您可以通过将双引号放在与您的单引号字符串相邻的双引号中来包含单引号 - '"foo"'"'""foo"单引号中的双引号内的',因此"foo"';和"'可以表示为'"',与"'"相邻。因此,包含双引号foo"'bar的单引号字符串可以用'foo"'"'bar"相邻引用,或者对于这种情况可能更现实些,'foo"'"'"相邻,与另一单引号字符串'bar'相邻,产生'foo'"'"'bar'

sed 's/^\(\(\\.\|[^\#"'"'"']*\|"\(\\.\|[^\"]\)*"\|'"'"'\(\\.\|[^\'"'"']\)*'"'"'\)*\)#.*/\1/p' file 

这是在Linux上测试的;在其他平台上,sed方言可能略有不同。例如,您可能需要在分组和修改操作符之前省略反斜杠。

唉,如果你可能有多行引用的字符串,这是行不通的; sed按设计,一次只检查一条输入线。您可以构建一个复杂的脚本,将多行内容收集到内存中,但到那时,切换到例如Perl开始很有意义。

-1
sed 's:^#\(.*\)$:\1:g' filename 

假设行以单个#注释开头,上面的命令将删除文件中的所有注释。

+0

//,那些有评论的行,但是不要以'#'开头? –

2

要删除注释行(线,其第一非空白字符是#),但认领行(行其第一字符是#!):

sed '/^[[:space:]]*#[^!]/d; /#$/d' file 

的第一个参数sed是含有串一个sed程序,包含两个删除行命令,格式为/regex/d。命令由;分隔。第一个命令删除注释行,但不删除行。第二个命令删除所有剩余的空注释行。它不处理尾随评论。

的最后一个参数sed是用作输入文件。在bash中,你还可以在一个字符串变量像这样操作:

sed '/^[[:space:]]*#[^!]/d; /#$/d' <<< "${MYSTRING}" 

例子:

# test.sh 
S0=$(cat << HERE 
#!/usr/bin/env bash 
# comment 
    # indented comment 
echo 'FOO' # trailing comment 
# last line is an empty, indented comment 
    # 
HERE 
) 
printf "\nBEFORE removal:\n\n${S0}\n\n" 
S1=$(sed '/^[[:space:]]*#[^!]/d; /#$/d' <<< "${S0}") 
printf "\nAFTER removal:\n\n${S1}\n\n" 

输出:

$ bash test.sh 

BEFORE removal: 

#!/usr/bin/env bash 
# comment 
    # indented comment 
echo 'FOO' # trailing comment 
# last line is an empty, indented comment 
    #  


AFTER removal: 

#!/usr/bin/env bash 
echo 'FOO' # trailing comment 
相关问题