如何删除以"//"开头的行(例如文件头部)?这些行位于文件开头。

4
我想从所有文件中删除标题,标题包含以//开头的行。
如果我想要删除所有以//开头的行,可以执行以下操作:
sed '/^\/\//d'

但这并不是我需要做的事情。我只需要删除文件开头以//开头的行。

样本文件:

// This is the header
// This should be deleted
print "Hi"
// This should not be deleted
print "Hello"

期望的输出结果:

print "Hi"
// This should not be deleted
print "Hello"

更新: 如果在开头或中间有新的换行符,它将不起作用。有没有办法处理这种情况?
样本文件:
< new empty line >
// This is the header
< new empty line >
// This should be deleted
print "Hi"
// This should not be deleted
print "Hello"

预期输出:

print "Hi"
// This should not be deleted
print "Hello"

有人能提供一种实现这个的方法吗?谢谢!

更新:已接受的答案可用于处理开头或中间的空格


请在您的问题中添加示例输入(无描述、无图像、无链接)和您对该示例输入的期望输出(无评论)。 - Cyrus
感谢您的建议,我已经更新了问题。 - Sweety
如果文件开头没有注释,是否应该删除任何空行? - Ed Morton
基本上这就是做你所要求的事情 (?m)(?:^\s*//.*\s*){2}。由于我不熟悉sed或awk的工作原理,因此我在注释中没有进行解释。但是,如果您尝试任何与此精确功能不同的操作,它将无法正常工作。 - user13843220
如果你能找到一个支持最小扩展正则表达式的引擎,那么这个选项可能是 ^(\s*\n\s*//.*){2}\n? 或者甚至是 ^\s*\n\s*//.*\s*\n\s*//.*\n?,它们不需要多行模式。 - user13843220
显示剩余3条评论
6个回答

5

请尝试以下操作。这也可以处理换行符的情况,已在https://ideone.com/IKN3QR中编写并测试。

awk '
(NF == 0 || /^[[:blank:]]*\/\//) && !found{
  next
}
NF{
  found=1
}
1
' Input_file

说明: 如果一行为空或以//开头并且找到的变量为NULL,则跳过该行。一旦发现没有//的行,就在此处设置变量找到,因此所有下一个出现的行都应从设置位置打印到输入文件的结尾。


1
差不多了!对于这个更新的问题,你的答案是有效的。我想知道在头部的 // 前如何处理空格?我尝试了你的解决方案并添加了空格,但没有起作用。 - Sweety
1
你需要使用/^[[:blank:]]*\/\//来匹配以注释开头的行,而不仅仅是包含注释的行。 - glenn jackman
2
我修改了“空白行”条件,以防空白行包含空格。 - glenn jackman
1
简单而有效的++ - anubhava
1
@Sweety,是的,我已经添加了它,看起来它正在工作,请让我知道这里是否有任何疑问。 - RavinderSingh13
显示剩余9条评论

2

使用 sed 命令:

sed -n '1{:a; /^[[:space:]]*\/\/\|^$/ {n; ba}};p' file
print "Hi"
// This should not be deleted
print "Hello"

GNU sed稍短的版本:

sed -nE '1{:a; /^\s*\/\/|^$/ {n; ba}};p' file

解释:
Explanation:
1 { # execute this block on the fist line only
    :a; # this is a label
     /^\s*\/\/|^$/ { n;  # on lines matching `^\s*\/\/` or `^$`, do: read the next line
          ba }           # and go to label :a
};  # end block
p   # print line unchanged:
    # we only get here after the header or when it's not found

sed -n命令使得sed不会打印没有p命令的任何行。

编辑:更新了模式以跳过空行。


这在GNU sed中有效。有什么想法可以使其适用于BSD和/或POSIX sed - chepner
@chepner 我不确定,但我的 man 手册说 -E 和 EREs 是 POSIX 支持的? - Lev Levitsky
我认为你必须使用 BREs 来处理 POSIX sed,但似乎很容易解决(只要你转义 |,GNU sed -n '...' 就可以正常工作)。而 BSD 的 sed 则似乎会引起问题。 - chepner
1
\s 明显是 GNU 的扩展;你可以使用 [[:space:]] 代替,但如果你知道你正在使用 GNU sed,那就明显不太方便。 - chepner
2
@Sweety,你知道“原地编辑”并不存在吗?当你使用 sed -i 'script' 命令时,它不是直接在原文件编辑,而是在内部复制一个文件,并在稍后用该副本覆盖原始文件。你可以使用任何命令 cmd 来执行相同的操作,只需编写 in_cmd() { for file; do cmd 'script' "$file" > tmp && mv tmp "$file"; done; }; in_cmd * 即可。不要因为想要进行“原地”编辑而牺牲你使用的工具/脚本,因为这是任何程序的简单部分。 - Ed Morton
显示剩余9条评论

2
我觉得你只是想从既不为空也不仅仅是注释的第一行开始打印:
$ awk 'NF && ($1 !~ "^//"){f=1} f' file
print "Hi"
// This should not be deleted
print "Hello"

上述代码会在找到这样的行时设置一个标志f,并打印从那时起的每一行。它可以在任何UNIX系统上的任何shell中使用任何awk来工作。
请注意,与发布的一些潜在解决方案不同,它不会在内存中存储超过1行的数据,因此无论您的输入文件有多大,它都可以正常工作。
它已经针对此输入进行了测试:
$ cat file

    // This is the header

// This should be deleted
print "Hi"
// This should not be deleted
print "Hello"

要在多个文件上运行上述操作并在进行操作时修改每个文件,可以使用GNU awk实现:
awk -i inplace 'NF && ($1 !~ "^//"){f=1} f' *

对于任何awk都适用的方法:

ip_awk() { local f t=$(mktemp) && for f in "${@:2}"; do awk "$1" "$f" > "$t" && mv -- "$t" "$f"; done; }

ip_awk 'NF && ($1 !~ "^//"){f=1} f' *

1
如果perl可用,则这种方法也可以在 slurp 模式下工作:
perl -0777 -pe 's~\A(?:\h*(?://.*)?\R+)+~~' file

\A 只匹配文件开头,(?:\h*(?://.*)?\R+)+ 匹配一个或多个空行或以可选前导空格的 // 开头的行。


0

使用GNU sed

sed -i -Ez 's/^((\/\/[^\n]*|\s*)\n)+//' file

^((\/\/[^\n]*|\s*)\n)+ 表达式将匹配以 // 开头的一个或多个行,还会匹配空行,仅限于文件开头。


这不是我想要的。它会从我的文件中删除以 // 开头的所有行。我想要的是:只移除以 // 开头的文件头,而不是任何其他以 // 开头的行。 - Sweety
@Sweety,我用GNU sed解决方案更新了答案。 - Ryszard Czech
它说 sed: 无效选项 -- 'z' - Sweety
@Sweety 这意味着你的 sed 不是 GNU sed。我还在开头添加了空行的匹配。 - Ryszard Czech

0

使用ed(基于流编辑器sed文件编辑器),

printf '1,/^[^/]/ g|^\(//.*\)\{0,1\}$| d\nw\n' | ed tmp.txt

可能需要一些解释。

ed以要编辑的文件名作为参数,并从标准输入读取命令。每个命令都以换行符结束。(您也可以从here文档中读取命令,而不是通过管道从printf读取。)

  1. 1,/^[^/]/寻址文件中的前几行,包括第一行不以/开头的行。(您想要删除的所有行都将包含在此集合中。)
  2. g|^\(//.*\)\{0,1\}$|d删除所有被寻址的空行或以//开头的行。
  3. w保存更改。

第二步有点丑陋;不幸的是,ed不支持您可能认为理所当然的正则表达式运算符,如?|。稍微分解一下正则表达式:

  1. ^ 匹配行的开头。
  2. //.* 匹配 // 后面跟着零个或多个字符。
  3. \(//.*\)\{0,1\} 匹配前面的正则表达式 0 或 1 次(即可选)
  4. $ 匹配行的结尾。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接