TL;DR- 下面的模式中发生了很多事情sed
,我不确定如何将离散的部分组合成一个整体命令。
重击版本:GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin21)
我正在通过逐个文件阅读 RBENV 代码库来学习 shell 脚本,并且我遇到过该rbenv-help
文件,其中包括这个函数定义:
extract_initial_comment_block() {
sed -ne "
/^#/ !{
q
}
s/^#$/# /
/^# / {
s/^# //
p
}
"
}
我明白这个函数是如何调用的在代码的下面,所以我知道它的第一个参数是一个文件名:
extract_initial_comment_block < "$filename" | collect_documentation
从这里我可以看到由“$filename”表示的文件被作为命令的标准输入sed
。就我的问题而言,连锁函数“collect_documentation”是无关紧要的。
我还从函数的名称中得知,它的目的是获取类似的文件这,并返回其摘要和使用注释,即链接文件的第 2-14 行。然而,我还没有测试过这个理论,所以我可能不是100%正确的。
此外,我知道来自这个 StackExchange 答案该标志的目的-e
是告诉sed
将后续字符串解释为命令(或由换行符分隔的命令集合?)。所以看起来主体extract_initial_comment_block
包含 3 个单独的脚本,用于sed
按顺序进行解释。同一个 StackExchange 答案说用于{...}
将命令分组在一起,但我不确定这是否是这个正则表达式(这些正则表达式?)中发生的情况。
据我所知,sed
这里有 3 个脚本:
/^#/ !{
q
}
s/^#$/# /
/^# / {
s/^# //
p
}
然而,即使在每个脚本中,也存在一些我无法识别的正在使用的模式(例如^#
和),即使在利用了诸如!{ q }
Linux 数据项目。看起来有很多动人的部分,我不确定每个脚本是如何组合成成品的。
我尝试尽可能清晰地阐述我的思考过程。到目前为止我的思路正确吗?如果不是,我哪里偏离了方向?如果是,我如何推断传递给的每个命令的含义sed
?
答案1
/^#/ !{ q }
斜杠之间的部分是正则表达式,其中^
表示字符串的开头,#
只是字符本身。该模式选择运行关联命令的行。尾随!
反转了匹配的含义,q
是退出的命令。因此,当 sed 程序看到一行时,它会退出不从评论标记开始#
。
s/^#$/# /
s/a/b/
s用 b 代替 a,^
是行首,$
是行尾,#
是它本身。因此,这将仅用一个单独的线更改#
为#
+空格。
/^# / { s/^# // p }
#
如果该行以 a和空格 ( /^# /
)开头,则将#
和 空格替换为空 ( s/^# //
) 并打印该行 ( p
)。这就是之前的替换派上用场的地方。
sed 的选项-n
(在命令开头)告诉 sed不是在执行脚本后打印该行,就像默认情况下一样。
请注意,该脚本会忽略以 a#
和开头的行不之后有一个空格,包括以该空格开头的 hashbang 行,#!
告诉操作系统该脚本使用哪个解释器。可能是故意的,但可能隐藏一些其他线路。
例如
#!/bin/sh
# some script
#
#this is ignored
# this prints
# this doesn't print any more
whatever
变成
some script
this prints