如何删除文件中的所有注释?


21

我有一个带有注释的文件:

foo
bar
stuff
#Do not show this...
morestuff
evenmorestuff#Or this

我只想打印所有未注释的代码:

foo
bar
stuff
morestuff
evenmorestuff

能够从文件中删除注释非常重要...有什么好的方法?


1
您无法使用grep删除行的一部分。您可以为此使用sed
miracle173

2
您的文字和示例矛盾。您写的是被注释掉的行,但显然从最后一行开始,您是指行部分。然后删除带注释的第一行(包括EOL),第二行可能被删除,但不清楚,因为那是最后一行。请重新表述“注释掉的行”以保持准确,并消除您的示例歧义。
Anthon 2014年

5
尝试使用 awk -F\# '$1!="" { print $1 ;} '
Archemar

2
如何echo '#' # output a #处理一条线?
库桑兰达

3
@Questionmark我可能很聪明,但是我写的不是一个shell-grammar-parser聪明的代码。
库萨兰达

Answers:


40

删除所有注释的一种方法是grep-o选项一起使用:

grep -o '^[^#]*' file

哪里

  • -o:仅打印行中匹配的部分
  • 第一^:行的开头
  • [^#]*:除#重复零次或多次外的任何字符

请注意,空行也将被删除,但是只有空格的行将保留。


2
我会使用grep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch

1
应当注意,这不是Shell脚本的通用方法,例如,该行将somvar='I am a long complicated string ## with special characters' # and I am a comment无法正确处理。
通配符

此变体对我而言更好(在Mac上):grep -o '^[^#].*' file
Pierz

评论不见了,但我在输出中看到一堆空白吗?sed解决方案只有一个空行,似乎是使用其他答案的可靠论据,除非我遗漏了什么?
JBallin

@JBallin您是否定义了一些别名grep?如果仍然在示例输入中看到空格,请尝试更改grepcommand grep
jimmij

31

我相信sed可以做的比这更好grep。像这样:

sed '/^[[:blank:]]*#/d;s/#.*//' your_file

说明

  • sed默认情况下,将逐行查看您的文件,并在可能在引号中应用了转换之后打印每行。(sed '' your_file只会将所有行打印不变)。
  • 在这里,我们给出了sed两条要在每行上执行的命令(它们之间用分号隔开)。
  • 第一条命令说:/^[[:blank:]]*#/d。用英语表示,这意味着如果该行在其开头与哈希匹配(以任意数量的前导空白开头),则删除该行(将不会打印)。
  • 第二个命令是:s/#.*//。在英语中,用一个井号代替后面的所有内容(直到该行的末尾),然后什么都没有(最后两个之间的空白都不是//)。
  • 总而言之,这将贯穿您的文件删除完全由注释组成的行,此后留下的任何行都将删除注释。

1
它还会删除字符串中的散列后找到的所有内容,不是吗?例如,mystring="Hello I am a #hash" 将成为 mystring="Hello I am a"
javadba

@javadba,是的,但是此时您最好使用完整的解析器。可以理解引号和变量分配但无法处理注释的数据将使用什么?(这就是为什么许多配置文件(例如,crontab仅允许全行注释,带或不带前导空格,但不允许在行末尾添加注释。逻辑更简单。在此答案中仅使用两个Sed指令中的第一个) (用于crontab注释剥离程序。)
通配符

很好的答案,这看起来在广泛的一般用例中实用性与复杂性之间取得了很好的平衡,但是如果您提前知道只需要删除直接以#(在第1列中)开头的行,有没有任何好处sedgrep -v "^#"
RBF06

4

您可以使用sed命令获得所需的输出。下面的命令为我完成了窍门。

sed 's/#.*$//g' FileName

哪里

  • #.*$-正则表达式会过滤所有的字符串,以开始#到行结束

在这里,我们需要删除这些行,因此我们将其替换为空,从而跳过“替换”部分。

  • g -提到重复搜索模式直到到达文件末尾。

sed的一般语法: s/regexp/replacement/flags FileName


2
注意:在这种情况下,第4行用新行替换。
αғsнιη

1
尝试使用包含该sed命令的脚本...
Kusalananda

它不会处理print "#tag" # Print a hashtag.
Ray Butterworth

3

正如其他人指出的那样,如果脚本的任何部分看起来像注释,但实际上却不是,则sed和其他基于文本的工具将无法正常工作。例如,您可以在字符串中找到一个#,或者找到一个常见的$#and ${#param}

我写了一个名为shfmt的shell格式化程序,它具有减少代码的功能。其中包括删除评论,其中包括:

$ cat foo.sh
echo $# # inline comment
# lone comment
echo '# this is not a comment'
[mvdan@carbon:12] [0] [/home/mvdan]
$ shfmt -mn foo.sh
echo $#
echo '# this is not a comment'

解析器和打印机是Go程序包,因此,如果您想使用自定义解决方案,编写20行Go程序以所需的确切方式删除注释应该相当容易。


2

您可以像这样使用反向匹配:

    #grep -v "#" filename

-v,--invert-match反转匹配感,以选择不匹配的行。(-v由POSIX指定。)


2
@alinh感谢您查看答案。请注意,该问题不仅需要行的开头,而且还需要文件中的任何位置。这也显示在他/她对上述问题的预期结果中。如果我只寻找行首,我的答案将是错误的。
拉扎2014年

zzz。我不好,没有看到最后一行:(
alinh 2014年

1
这将完全删除evenmorestuff以OP的示例开头的行。
约瑟夫R.14年

@JosephR。接得好。我想念那个。在这种情况下grep -o '^[^#]*' file将是最好的解决方案。吉米吉已经对此进行了解释。感谢您的评论
Raza 2014年

它不会处理print "#tag" # Print a hashtag.
Ray Butterworth

2

我喜欢约瑟夫(Joseph)的答案,但也需要它除去//注释,因此我对其进行了稍微修改并在Redhat上进行了测试

# no comments alias
alias nocom="sed -E '/^[[:blank:]]*(\/\/|#)/d;s/#.*//' | strings"

# example
cat SomeFile | nocom | less

我敢打赌,有一种比使用字符串删除空行更好的方法,但这是我使用的快速而肮脏的解决方案。

-干杯


它不会处理print "#tag" # Print a hashtag.
Ray Butterworth


1
cat YOUR_FILE | cut -d'#' -f1

#用作列分隔符,仅保留第一列(即之前的所有内容#)。


1
如果YOUR_FILE脚本包含这些命令,则该脚本将留cat YOUR_FILE | cut -'在该行的文件中。
库萨兰达

1

使用像

egrep -v "#|$^" <file-name> 

:-v:将进行反向匹配

:#:将匹配以#开头的所有行

:$ ^:将匹配所有空白行


1
不,#将匹配行中的任何位置,并删除整行。
ilkkachu

1

最好的解决方案是使用以下命令:

sed -i.$(date +%F) '/^#/d;/^$/d' ntp.conf

-i是就地编辑,但是紧随其后的前缀告诉sed创建备份。在这种情况下,使用日期扩展名(ntp.conf.date),我们运行两个命令,每个命令都有一个地址空间,第一个命令删除注释行,第二个命令用分号与第一个分隔,删除空白行。

我在:theurbanpenguin.com找到了这个解决方案


0

其他答案似乎都没有做到这一点,它们要么留空行,要么留在注释不在第一个字符处的行。我最终使用了这个:

cat << EOF >> ~/.bashrc
alias nocom='sed -e "/^\s*#/d" -e "/^\s*$/d"'
EOF

这将设置一个别名,这样您就不必记住它了(开头是不可能的)。打开一个新会话,您将拥有新nocom命令。那你就可以

nocom /etc/foobar.conf

干杯。


1
.*$在第一个正则表达式中匹配没有什么意义-锚点没有用,并且您没有捕获要替换的匹配文本。仅使用^\s*
Jeff Schaller

它不会处理print "#tag" # Print a hashtag.
Ray Butterworth

0

在Joseph R.的第二个答案之后,我添加/^$/d了删除空白行。

sed '/^[[:blank:]]*#/d;s/#.*//;/^$/d'

-1

在阅读完其他内容并附上说明后,我将发布最适合我的方法,并且似乎最有意义。几篇文章接近了,但我还不能发表评论(因为我是新手):

grep -E -v "(^#.*|^$)" filename
  • -E =将以下模式解释为正则表达式,类似于使用egrep
  • -v =打印图案的反转(将打印与表达式不匹配的行)
  • "(^#.*|^$)"=这有一个指定OR语句的管道。该表达式表示要打印以#(以及其后的其他任何内容)开头的任何行,或者在该行的开头和结尾之间打印零字符的任何行。

-v会在屏幕上打印的反转,这将是与字符的任何行不以启动#


它不会处理print "#tag" # Print a hashtag.
Ray Butterworth

啊,对...当然。感谢您指出了这一点。我一直在寻找有关典型Linux配置文件(例如pam.d configs)的答案,所以我没有想到这一点。我猜想必须将其修改为查找和删除与代码位于同一行的任何注释。我刚刚在上面看到了针对我的特定问题的更好解决方案:egrep -v“#| $ ^”
jackbmg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.