289

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

CLIENTSCRIPT="foo"
CLIENTFILE="bar"

我想在该行之后插入一行,CLIENTSCRIPT=导致...

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

8 回答 8

426

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

sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

如果您想就地替换,请使用

sed -i '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

输出

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

文档

于 2013-03-21T22:27:07.867 回答
61

注意标准sed语法(如在 POSIX 中,所有符合标准的sed实现都支持(GNU、OS/X、BSD、Solaris...)):

sed '/CLIENTSCRIPT=/a\
CLIENTSCRIPT2="hello"' file

或者在一行:

sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file

-expressions(和 iles 的内容-f)与换行符连接起来组成 sed 脚本sed解释)。

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

或者,为了便携性,您可以perl改用:

perl -pi -e '$_ .= qq(CLIENTSCRIPT2="hello"\n) if /CLIENTSCRIPT=/' file

或者你可以使用edor ex

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file
于 2014-08-14T10:53:49.707 回答
20

使用以下s命令的 POSIX 兼容:

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file
于 2016-12-20T20:51:40.887 回答
17

在 MacOS(至少,OS 10)和 Unix 上工作的 Sed 命令(即不需要像 Gilles'(当前接受)那样的 gnu sed):

sed -e '/CLIENTSCRIPT="foo"/a\'$'\n''CLIENTSCRIPT2="hello"' file

这适用于 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 解释并且可能不一样,就像\nis - 例如。\0将是匹配的第一行。如果您要添加来自变量的行,否则您必须先使用 ${var//} 或另一个 sed 语句等来转义所有内容,则特别方便。

当您不想将 a 命令的替换文本放在行首(如果在函数中)带有缩进线。我利用了 $'\n' 被 shell 评估为换行符的优势,它不在常规的 '\n' 单引号值中。

尽管我认为 perl/甚至 awk 可能会因为更具可读性而获胜,但它已经足够长了。

于 2018-01-23T16:26:06.807 回答
8

对此发布答案可能有点晚,但我发现上述一些解决方案有点麻烦。

我在 sed 中尝试了简单的字符串替换,它起作用了:

sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

&符号反映匹配的字符串,然后添加 \n 和新行。

如前所述,如果您想就地执行此操作:

sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

另一件事。您可以使用表达式进行匹配:

sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file

希望这可以帮助某人

于 2019-02-12T14:06:34.160 回答
5

awk 变体:

awk '1;/CLIENTSCRIPT=/{print "CLIENTSCRIPT2=\"hello\""}' file
于 2019-08-02T07:40:54.073 回答
1

我有一个类似的任务,并且无法使上述 perl 解决方案正常工作。

这是我的解决方案:

perl -i -pe "BEGIN{undef $/;} s/^\[mysqld\]$/[mysqld]\n\ncollation-server = utf8_unicode_ci\n/sgm" /etc/mysql/my.cnf

解释:

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

[mysqld] collation-server = utf8_unicode_ci

有效地collation-server = utf8_unicode_ci在包含[mysqld].

于 2015-07-07T20:15:03.447 回答
0

我最近也必须为 Mac 和 Linux 操作系统执行此操作,并且在浏览了许多帖子并尝试了很多事情之后,在我看来,我从来没有到达我想要的地方:一个足够简单的使用众所周知的解决方案和具有简单模式的标准命令,一个班轮,便携,可扩展以添加更多约束。然后我尝试从不同的角度看待它,那时我意识到如果“2-liner”满足我的其他标准,我可以不使用“one liner”选项。最后我想出了这个我喜欢的解决方案,它适用于 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 选择第一次出现,并且算术 op 将第一次出现的行号增加 1,因为我想在出现之后插入。在第二个命令中,它是一个就地文件编辑,“i”用于插入:ansi-c 引用新行,“bar”,然后是另一个新行。结果是在“foo”行之后添加了一个包含“bar”的新行。这两个命令中的每一个都可以扩展为更复杂的操作和匹配。

于 2020-05-11T06:05:42.543 回答