目标:删除每个注释块中除最后一行以外的所有注释行。如果文件以注释块结尾,请将其完全删除。每个注释行都以
#
.我尝试过的命令
sed -z -e 's/#.*\n#/#/g' "${InputP}"
输入文件
# Life/Living # Life/Passion - [Mindfulness.md](file:///home/nikhil/Documents/Git/Life/Passion/PassionSrc/Sports/Yoga/Mindfulness/Mindfulness.md) # Life/PersonalManagement # Life/Social # Linux/AmazingNotes # Linux/Backintime # Linux/DotFiles # Linux/GitScripts - [Peaceful.m3u](file:///home/nikhil/Documents/Git/../Mobile/Documents/PortableNotes/PortableNotesSrc/SocialActivity/Music/SongsPlaylist/Data/Peaceful.m3u) - [AuxiliaryFiles.sh](file:///home/nikhil/Documents/Git/Linux/GitScripts/GitScriptsSrc/GitInit/GitNew/Src/AuxiliaryFiles.sh) # PythonWs/NumericalProgramming # PythonWs/Python # PythonWs/ScientificComputing
预期输出
# Life/Passion - [Mindfulness.md](file:///home/nikhil/Documents/Git/Life/Passion/PassionSrc/Sports/Yoga/Mindfulness/Mindfulness.md) # Linux/GitScripts - [Peaceful.m3u](file:///home/nikhil/Documents/Git/../Mobile/Documents/PortableNotes/PortableNotesSrc/SocialActivity/Music/SongsPlaylist/Data/Peaceful.m3u) - [AuxiliaryFiles.sh](file:///home/nikhil/Documents/Git/Linux/GitScripts/GitScriptsSrc/GitInit/GitNew/Src/AuxiliaryFiles.sh)
- 但我得到这个输出
# PythonWs/ScientificComputing
有谁知道如何解决这个问题?
答案1
问题是它.*
是贪婪的,因此sed -z -e 's/#.*\n#/#/g'
将从包含 的第一行#
开始匹配到以 开头的最后一行#
。这只是因为-z
标志而发生,它一次吸收模式空间中的整个文件(假设文本文件中没有空字节)。
解决你的问题的 Sed 脚本是
sed -n '/^#/N;/\n#/D;p' file
/^#/N
如果该行以 开头#
,则将下一行追加到模式空间。/\n#/D
如果模式空间包含换行符后跟#
,则删除换行符之前的所有内容并开始新的循环。p
如果到达此命令,则打印模式空间。
有用的链接
答案2
您显然希望从输入中删除后面跟着其他注释行的所有注释行。调用sed
失败,因为默认使用正则表达式“贪婪的”(即尽可能多的消费),这是不容易改变的。
所以我将为awk
既定目标添加一个基于 - 的解决方案:
awk '/^#/{buf=$0;next} {if (buf) {print buf; buf=""}}1' "${InputP}"
或者,稍微更紧凑:
awk '/^#/{buf=$0;next} buf{print buf; buf=""}1' "${InputP}"
- 这将打印所有不是注释行的行(
1
规则块外部意味着“打印当前行,包括迄今为止所做的所有修改” - 在本例中没有)。 - 如果遇到注释行(该行与模式匹配
/^#/
),内容将存储在 buffer 中buf
,但尚未打印。该next
命令会跳到下一行执行,因此其余代码仅适用于非注释行。 - 如果遇到非注释行,则首先打印缓冲区内容(如果有),并在打印实际行内容之前清空缓冲区(以防止多次打印输出)。
答案3
使用GNU sed
slurp 模式-z
并利用扩展的正则表达式,-E
我们可以执行如下操作:
$ sed -Ez '
s/(^|\n)(#[^\n]*\n)+$/\1/
s/(^|\n)(#[^\n]*\n)+/\1\2/g
' file
- 删除尾随注释块。
- 删除所有注释块,但保留每个注释块的最后一行。
GNU sed模型如下:
- sed 逐行读取文件,除非
-z
有效,否则它会读取整个文件。记录分隔符默认为换行符,\n
除非-z
正在使用,否则它是\0
NULL ascii。 - 读入记录后,尾随记录分隔符被剪掉,并将结果字符串存储在模式空间寄存器中。模式空间是所有 sed 命令运行的地方。
- 现在假设
sed
我们的脚本中有 5 个命令sed
。然后将第一个命令应用于模式空间,这会修改模式空间,并在此修改后的模式空间上sed
应用下一个命令......依此类推,直到最后一个。然后,stdout
除非-n
有效,否则将打印模式空间。此后,读入下一条记录并将相同的sed
命令序列应用于模式空间。
请注意,上面是一个非常简化的叙述,当脚本中没有使用流控制命令时有效sed
。
是的,你是对的,在 slurp 模式下,它$
表示文件结束,也表示模式空间结束,因为只有一个模式空间。
当您拥有此构造时(regex)+
,由于正则表达式的贪婪本质,括号将保存最后一个正则表达式匹配。
或者,也可以这样做
$ sed -e '
/^#/{h;d;}
H;z;x;s/^\n//
' file
答案4
这应该有效:
perl -ne 'print $x,$_ unless /^#/; $x = /^#/ ? $_ : ""' < infile
我得到了您发布的预期输出。
编辑:解释
- 如果你愿意的话,就当作
$x
是:-)$left_over_line_to_be_printed
- 第一个语句打印任何剩余行,然后打印当前行(如果当前行不是标题行)。
- 第二条语句将“leftover”设置为最后看到的标题行,或者设置为空字符串。 (也就是说,对于非标题行,“剩余”将是空字符串,因为它已经由第一个语句打印。对于标题行,它将是该行。如果多个标题行聚集在一起,它将最终成为最后一个)。