Shell 使用sed在第一次匹配后插入行

Shell 使用sed在第一次匹配后插入行,shell,sed,Shell,Sed,出于某种原因,我似乎找不到一个直截了当的答案,我现在有点时间紧张。如何使用sed命令在与特定字符串匹配的第一行之后插入文本的选择行。我有 CLIENTSCRIPT="foo" CLIENTFILE="bar" 我想在CLIENTSCRIPT=行之后插入一行,结果是 CLIENTSCRIPT="foo" CLIENTSCRIPT2="hello" CLIENTFILE="bar" 尝试使用GNU sed执行此操作: sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT

出于某种原因,我似乎找不到一个直截了当的答案,我现在有点时间紧张。如何使用
sed
命令在与特定字符串匹配的第一行之后插入文本的选择行。我有

CLIENTSCRIPT="foo"
CLIENTFILE="bar"
我想在
CLIENTSCRIPT=
行之后插入一行,结果是

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

尝试使用GNU sed执行此操作:

sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file
如果要就地替换,请使用

输出 医生
  • 请参阅并搜索
    \a
    (附加)

请注意标准的
sed
语法(与POSIX中一样,因此受到周围所有一致的
sed
实现(GNU、OS/X、BSD、Solaris…)的支持):

或在一行上:

sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file
-e
xpressions(以及
-f
iles的内容)用换行符连接起来,组成sed脚本
sed
解释)

用于就地编辑的
-i
选项也是GNU扩展,一些其他实现(如FreeBSD)支持
-i'

或者,为了便于移植,您可以使用
perl

perl -pi -e '$_ .= qq(CLIENTSCRIPT2="hello"\n) if /CLIENTSCRIPT=/' file
或者您可以使用
ed
ex

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file

我有一个类似的任务,无法让上面的perl解决方案工作

以下是我的解决方案:

perl-i-pe“BEGIN{undef$/;}s/^\[mysqld\]$/[mysqld]\n\n安装服务器=utf8\u unicode\u ci\n/sgm”/etc/mysql/my.cnf

说明:

使用正则表达式搜索my/etc/mysql/my.cnf文件中仅包含
[mysqld]
的行,并将其替换为

[mysqld]
排序规则服务器=utf8\U unicode\U ci


使用
s
命令将
collation server=utf8\u unicode\u ci
行有效地添加到包含符合POSIX的
[mysqld]
行之后:

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file

在MacOS(至少是OS 10)和Unix上运行的Sed命令(即,不需要像Gilles(目前接受)那样的gnu Sed):

这适用于bash,也可能适用于其他了解$'\n'求值引号样式的shell。任何东西都可以在同一条线上工作 旧的/POSIX sed命令。如果可能有多行与CLIENTSCRIPT=“foo”(或您的等效项)匹配,并且您只希望在第一次添加额外的行,那么您可以按如下方式对其进行返工:

sed -e '/^ *CLIENTSCRIPT="foo"/b ins' -e b -e ':ins' -e 'a\'$'\n''CLIENTSCRIPT2="hello"' -e ': done' -e 'n;b done' file
(这会在插入行代码之后创建一个循环,循环遍历文件的其余部分,再也不会返回到第一个sed命令)

您可能会注意到,我在匹配模式中添加了一个“^*”,以防该行出现在注释中或缩进。它不是100%完美,但涵盖了一些可能常见的其他情况。根据需要调整

这两种解决方案还解决了一个问题(对于添加一行的通用解决方案),即如果新插入的行包含未替换的反斜杠或符号,它们将被sed解释,并且可能不会出现相同的结果,就像
\n
是-例如,
\0
将是匹配的第一行。如果要添加来自变量的行,则必须先使用${var/}或其他sed语句等对所有内容进行转义,这一点尤其方便

如果您不想将a命令的替换文本放在一行的开头(例如,在具有缩进行的函数中),则此解决方案在脚本中的混乱程度会稍低一些(即引用和\n不容易阅读)。我利用了shell将$'\n'计算为换行符的优势,它不是常规的'\n'单引号值


虽然时间越来越长,我认为perl/甚至awk可能会因为可读性更强而获胜。

对此给出答案可能有点晚,但我发现上面的一些解决方案有点麻烦

我在sed中尝试了简单的字符串替换,它成功了:

sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file
&符号反映匹配的字符串,然后添加\n和新行

如前所述,如果您想在适当的位置执行此操作:

sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file
还有一件事。可以使用表达式进行匹配:

sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file
希望这有助于人们了解awk变体:

awk '1;/CLIENTSCRIPT=/{print "CLIENTSCRIPT2=\"hello\""}' file

我最近也不得不为Mac和Linux操作系统做这件事,在浏览了许多帖子并尝试了许多东西之后,我认为我从未达到我想要达到的目的,那就是:一个简单到足以理解的解决方案,使用众所周知的标准命令,使用简单的模式,一行代码,可移植,可展开以添加更多约束。然后我试着从另一个角度来看待它,那时我意识到,如果“两行”符合我的其他标准,我就可以不用“一行”选项。最后,我提出了这个解决方案,我喜欢它在Ubuntu和Mac上都能运行,我想与大家分享:

insertLine=$(( $(grep -n "foo" sample.txt | cut -f1 -d: | head -1) + 1 ))
sed -i -e "$insertLine"' i\'$'\n''bar'$'\n' sample.txt
在第一个命令中,grep查找包含“foo”的行号,cut/head选择第一个引用,算术运算将第一个引用行号增加1,因为我想在引用之后插入。
在第二个命令中,它是一个就地文件编辑,“i”用于插入:一个ansi-c引用新行,“bar”,然后是另一个新行。结果是在“foo”行之后添加一个包含“bar”的新行。这两个命令中的每一个都可以扩展到更复杂的操作和匹配。

谢谢!要让它在不打印文件内容的情况下写回文件,请注意,两者都假定GNU
sed
。这不是标准的
sed
语法,不能与任何其他
sed
实现一起使用。我很难让它对我起作用,因为我使用了不同的分隔符。在RTFM'ing之后,我意识到我必须以\开始正则表达式,然后是分隔符。它如何仅适用于第一个匹配?很明显,它会在匹配后添加文本,但它如何只知道第一个匹配?这会在每个匹配后添加文本,对我来说……甚至支持插入新行。我喜欢!另请参见
sed-e'/../s/$/\'-e'CLI…/'<
sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file
sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file
awk '1;/CLIENTSCRIPT=/{print "CLIENTSCRIPT2=\"hello\""}' file
insertLine=$(( $(grep -n "foo" sample.txt | cut -f1 -d: | head -1) + 1 ))
sed -i -e "$insertLine"' i\'$'\n''bar'$'\n' sample.txt