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
}
"
}
我看到如何在代码中进一步调用此函数,所以我知道它的第一个 arg 是文件名:
extract_initial_comment_block < "$filename" | collect_documentation
从这里我可以看到由“$filename”表示的文件被作为标准输入提供给sed
命令。就我的问题而言,连锁功能“collect_documentation”是无关紧要的。
我还从函数的名称中得知,它的目的是获取这样的文件,并返回其摘要和使用注释,即链接文件的第 2-14 行。但是,我还没有测试过这个理论,所以我可能不是 100% 正确的。
此外,我从这个 StackExchange 答案中知道,标志的目的-e
是告诉sed
将后续字符串解释为命令(或由换行符分隔的命令集合?)。因此,它的主体看起来extract_initial_comment_block
包含 3 个单独的脚本,sed
以便按顺序进行解释。相同的 StackExchange 答案说{...}
用于将命令组合在一起,但我不确定这是否是这个正则表达式(这些正则表达式?)中发生的事情。
据我所知,这里有 3 个脚本sed
:
/^#/ !{
q
}
s/^#$/# /
/^# / {
s/^# //
p
}
但是,即使在这些脚本中的每一个中,都使用了一些我无法识别的模式(例如^#
和),即使在利用了Linux Data Project之类的资源之后也是如此。似乎有很多动人的部分,我不确定每个脚本是如何组合成成品的。!{ q }
我试图以尽可能清晰的方式走过我的思考过程。到目前为止,我的思路正确吗?如果不是,我在哪里偏离了航线?如果是,我如何推断传递给的每个命令的含义sed
?
斜线之间的部分是正则表达式,其中
^
表示字符串的开头,#
只是字符本身。该模式选择运行相关命令的行。尾随!
反转匹配的意义,q
是退出的命令。因此,当 sed 程序看到不以注释标记开头的行时,它会退出该程序#
。s/a/b/
s用 b 代替 a,^
是行首,$
行尾,#
是它自己。所以这改变了一行,只有一个单独的#
到#
+空格。如果该行以 a
#
和空格 (/^# /
) 开头,则将和空格替换为#
空 (s/^# //
) 并打印该行 (p
)。这是以前的替换派上用场的地方。sed的
-n
选项(在命令的开头)告诉 sed在执行脚本后不打印该行,默认情况下会这样做。请注意,脚本会忽略以 a 开头且
#
后面没有空格的行,包括以它开头的 hashbang 行#!
,告诉操作系统要为脚本使用哪个解释器。可能是故意的,但可能会隐藏其他一些行。例如
变成