说明:使用 GNU sed。
现状 - ~/.screenrc,最后几行:
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop
# name thrashmetal
# screen -t script emacs -nw /home/$USER/bin/thrashmetal
# number 1
# split -v
# focus
# chdir "/home/$USER/thrashmetal/src"
# screen -t scr watch nl asdkjlek.html
# number 2
# focus
# split
# focus
# screen -t output watch thrashmetal asdkjlek.html
# number 3
# focus
# split
# focus
# chdir "/home/$USER/thrashmetal/plan"
# screen -t soll watch less soll
# number 4
# focus
# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave
目的:
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop
name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus
# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave
我当前的尝试几乎可以完成工作,但一旦出现该行就无法停止,这只是一个新行,没有任何注释符号或字母数字字符:
sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc
解释、意图:
'
一系列要做的事情的开始s
代替+
使用“+”作为分隔符# …
逐行浏览,直到找到以“#”开头的行...\(
启动组以供稍后反向参考name thrashmetal
并继续“名称thrashmetal”\)
组结束+\1+
仅用组部分替换该行中的第一个匹配项,不带“#”;
然后,从那时起,做另一件事……:a
做一个名为“a”的循环;s
对于接下来的每一行,您逐行替换...+
设置“+”作为分隔符#
该行中“#”的第一个匹配项,无论该行中其后的内容如何...++
什么都没有,有效地删除它;ta
只要你失败了,就这样做,这应该是当你到达段落末尾,然后是分隔 thrashmetal-block 和 darkwave-block 的 2 个换行符,然后返回到“a”所在的位置'
一系列要做的事情的结束.screenrc
执行有关我当前目录中的文件“.screenrc”的一系列操作 - 我的主目录
标准输出:
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop
name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus
name darkwave
screen -t script emacs -nw /home/$USER/bin/darkwave
如何解决这个问题?我做错了什么,循环不会在到达 thrashmetal 段落末尾时立即停止,而是简单地跳到下一段(darkwave 段落)并继续?
我猜想,那个循环中的任何东西都一定是错误的……也许是“t”,但“T”或“b”也不会删掉它……
这将应用替换,
#
从范围内的每一行中删除初始和后续的空格字符。该范围从匹配的行开始
^# name thrashmetal$
,到第一个后续匹配的行^$
(空行)结束。或者,直接翻译成
awk
:此处,尾随
1
是{ print $0 }
or的缩写{ print }
,导致输出当前(可能已修改)行(文本的打印在脚本中是隐式的sed
)。对于任何对
ed
编辑器感兴趣的人,您可以使用以下编辑命令来解决此问题:这会将光标移动到所需段落的第一行,并将替换应用于该行以及后面的所有行,直到到达空行。
我们不能使用
...因为地址是相对于当前行计算的,并且当我们启动编辑器时当前行位于文件的末尾。由于我们位于文件的末尾,因此命令中的范围将无效,因为地址
/^$/
将是比起始地址更早的行(相对于当前行,第一个空行位于段落开头之前) 。您自己的方法已更正(将分隔符从加号更改为默认值并分成多个表达式,这样更便携):
我没有进行初始替换,而是让段落初始行的匹配来确定是否跳过编辑脚本的其余部分。
b
如果未遇到该行,则跳过该行。如果找到该行,我们将对其进行修改并创建标签
a
。然后,我们打印当前缓冲区并使用下一行替换其内容n
。循环像以前一样继续,#
如果缓冲区的内容发生变化,则删除子字符串并循环回标签。您最初尝试的主要问题是,
...是“
a
-loop”是无条件的,因此适用于输入的每一行,无论初始替换是否成功或失败(您显示前两行不受命令影响,但我认为这是一个复制粘贴错误)。该循环也不会读取下一行,因此它只会在每行上运行一次#
(除非在一行上找到多个子字符串)。我的修复方法是将初始替换分为测试和替换,然后确保“
a
-loop”读取下一行输入,直到替换失败。我也不会替换#
任何一行上的多个或嵌入(内部)字符串,只会替换行开头的第一个字符串。这个脚本似乎可以做你想做的事:
我们有效地将事物分割成空行分隔的块。当我们找到以 开头的块时
# name thrashmetal
,我们删除#
行开头的所有字符串。给定您的示例输入,这将产生输出:
带注释的 sed 脚本:
您还可以考虑使用 awk:
在这里,通过将 RS(输入记录分隔符)设置为空白,您可以将段落视为单行。
使用任何 awk: