出于某种原因,我似乎无法找到一个直截了当的答案,而且我现在有点紧张。在使用sed
命令匹配特定字符串的第一行之后,如何插入选择行文本。我有......
CLIENTSCRIPT="foo"
CLIENTFILE="bar"
我希望在CLIENTSCRIPT=
行之后插入一行,从而产生...
CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"
答案 0 :(得分:330)
尝试使用GNU sed:
sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file
如果您想替换就地,请使用
sed -i '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file
CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"
\a
(追加)答案 1 :(得分:43)
请注意标准的sed
语法(如POSIX所示,所有符合sed
的实现都支持(GNU,OS / X,BSD,Solaris ...)):
sed '/CLIENTSCRIPT=/a\
CLIENTSCRIPT2="hello"' file
或者在一条线上:
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
答案 2 :(得分:12)
符合POSIX标准的s
命令:
sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file
答案 3 :(得分:5)
Sed命令适用于MacOS(至少OS 10)和Unix一样(即不需要像Gilles(目前接受)那样的gnu sed):
sed -e '/CLIENTSCRIPT="foo"/a\'$'\n''CLIENTSCRIPT2="hello"' file
这适用于bash,也可能是其他shell,它们知道$'\ n'评估报价样式。一切都可以在一条线上工作 old / 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解释,可能不会相同,就像{ {1}}是 - 例如。 \n
将是匹配的第一行。特别方便的是,如果你要添加一个来自变量的行,你必须先使用$ {var //}或其他sed语句等来逃避所有内容。
这个解决方案在脚本中不那么混乱(引用和\ n不容易阅读),当你不想在行的开头放置a命令的替换文本时,如果说,在具有缩进线的函数中。我已经利用shell将$'\ n'评估为换行符,而不是常规'\ n'单引号值。
虽然我认为perl /甚至awk可能因为更具可读性而获胜,但它已经足够长了。
答案 4 :(得分:1)
awk变体:
awk '1;/CLIENTSCRIPT=/{print "CLIENTSCRIPT2=\"hello\""}' file
答案 5 :(得分:0)
我有类似的任务,并且无法使上述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]
行。
答案 6 :(得分:0)
为此发布答案可能有点晚,但是我发现上述解决方案有些繁琐。
我在sed中尝试了简单的字符串替换,并且有效:
sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file
&符号反映了匹配的字符串,然后添加\ n和新行。
如前所述,如果您想就地进行:
sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file
另一件事。您可以使用表达式进行匹配:
sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file
希望这对某人有帮助
答案 7 :(得分:0)
我最近在Mac和Linux OS上也必须这样做,并且在浏览了许多文章并尝试了许多方法之后,我特别认为我从来没有想过要去的地方:一个简单易懂的解决方案使用具有简单模式的众所周知的标准命令,一根衬里,便携式,可扩展以添加更多约束。然后我尝试以不同的角度看待它,那时候我意识到,如果“ 2-衬里”满足我的其他标准,我可以不用“一个衬里”选项。最后,我想出了这个解决方案,我希望它可以在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”的新行。这两个命令中的每一个都可以扩展为更复杂的操作和匹配。