我正在尝试使用 sed 来更新带注释的配置文件。我并没有将所有内容都放在 EOF 处,而是尝试将所有内容分开。我的配置看起来像这样。
# SECTION ONE
data...
data...
data...
<insert line here>
# SECTION TWO
data...
data...
我试图在第一节的末尾插入行,但我很难编写搜索模式,因为它不允许“\n”,并且模式中不能有多个“^$” 。我想要如下的东西:
sed -i "/^\n\n# SECTION TWO.*/i data..." somefile.conf
or
sed -i "/^$^$# SECTION TWO.*/i data..." somefile.conf
我也愿意接受其他建议,但如果可能的话,我想将其保留在一行中。这是一个更大的脚本的一部分。我知道使用 Python、Perl 等非常容易,但我试图将其保留为“shell”解决方案。
答案1
使用awk
代替sed
:
newdata='This is the new data'
newdata=$newdata awk -F '\n' -v OFS='\n' -v RS= -v ORS='\n\n' \
'$1 == "# SECTION ONE" { $(NF+1) = ENVIRON["newdata"] }; 1' file
或者
newdata='This is the new data'
newdata=$newdata awk '
BEGIN { FS = OFS = "\n"; RS = ""; ORS = "\n\n" }
$1 == "# SECTION ONE" { $(NF+1) = ENVIRON["newdata"] }; 1' file
这通过使用输入记录分隔符awk
的空值来进入“段落阅读模式” 。RS
这意味着awk
一次将阅读一个段落。 “段落”是由至少一个空行分隔的任何行的集合。
然后,我们将输入字段分隔符FS
设为换行符,-F '\n'
以便段落中的每一行都成为其自己的字段。
我们还设置了与输出相关的相应变量ORS
,OFS
使得记录(段落)以尾随空行输出,字段(段落内的行)以换行符结束输出。
实际代码检测段落的第一行何时正是字符串# SECTION ONE
。如果是这种情况,则会将新字段添加到包含新数据的当前记录的末尾。新数据取自newdata
环境变量。
所有段落,无论是否修改,都会无条件输出。
请注意,如果实际的配置文件(我们在问题中从未看到)是用 XML、YAML、JSON 或其他结构化文档格式编写的,那么答案是无效的,如那些文档格式要求用于读取和写入的正确格式感知工具(因为它们不是面向行的并且数据需要编码/解码)。
答案2
使用 GNU sed 我们可以执行以下操作:
sed -e '/# SECTION ONE/,/^$/s/^$/__NEW-DATA__\n/' file
awk 中的范围运算符可用于获得所需的输出
awk '
/# SECTION ONE/,!NF{
if (!NF) print "__NEW-DATA__"
}1
' file
此方法使用 POSIXly sed 构造
sed -e '
/# SECTION ONE/!b
:a
n;/^$/!ba
G;s/^/__NEW-DATA__/
' file
在此方法中,我们将新数据放置在节名称之前,前提是它不是第一个数据。假设文件大小至少为 3 行。
sed -e '
1,2N
$q;N
s/^\n\n# SECTION TWO/__NEW-DATA__\n&/;t
P;D
' file
答案3
再次阅读Kusalandras的评论和问题后,我像他或她一样理解它。
GNU-sed 有一个打开 POSIX 风格的开关,所以我希望这次该命令与 sed 风格无关。
原始文件:
cat FILE
# SECTION ONE
data...
data...
data...
# SECTION TWO
data...
data...
命令:
sed --posix "s/^[ \t]*$/...new data .../; /# SECTION TWO/i\\ " FILE
# SECTION ONE
data...
data...
data...
...new data ...
# SECTION TWO
data...
data...
请注意,插入会在文件中留下空白,可以使用后续 sed 命令将其删除,也可以通过 useinds/^[ \t]*$
作为正则表达式来处理,它匹配空行以及空白和/或制表符的纯空白。
选择:
sed --posix "s/^$/...new data .../; /# SECTION TWO/i\ " -e "s/^ $//" FILE
第二种形式使用第二个 sed 命令(-e - 可以说,它是第三个,在使用两个命令之后,;
在第一个引号中分隔)来删除空格(如果不能容忍),因此在查找空行时是教条的。