Insert line after first match using sed

2019-01-05 08:16发布

For some reason I can't seem to find a straightforward answer to this and I'm on a bit of a time crunch at the moment. How would I go about inserting a choice line of text after the first line matching a specific string using the sed command. I have ...

CLIENTSCRIPT="foo"
CLIENTFILE="bar"

And I want insert a line after the CLIENTSCRIPT= line resulting in ...

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

标签: shell sed
6条回答
聊天终结者
2楼-- · 2019-01-05 08:47

A POSIX compliant one using the s command:

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file
查看更多
我命由我不由天
3楼-- · 2019-01-05 08:51

I had a similar task, and was not able to get the above perl solution to work.

Here is my solution:

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

Explanation:

Uses a regular expression to search for a line in my /etc/mysql/my.cnf file that contained only [mysqld] and replaced it with

[mysqld] collation-server = utf8_unicode_ci

effectively adding the collation-server = utf8_unicode_ci line after the line containing [mysqld].

查看更多
倾城 Initia
4楼-- · 2019-01-05 08:54

I recently had to deal with this but not just for one file but multiple different files that I just couldn't do by hand. So I had to find a script for it.

Script Download: kinglazy-autoinsert.sh

Usage:

kinglazy-autoinsert.sh (list_file) (pattern_file)

Explanation of parameters:

list_file = This is the file that contains the absolute path of the list of file(s) you want to edit

pattern_file = This is the file where you specify the pattern (in the first column) under which you want to add new text. The new text to add under the pattern is specified in the second column. And that's about it!

This script saves time and helps you get the job done with the smallest effort possible.

Dependencies: None

查看更多
萌系小妹纸
5楼-- · 2019-01-05 08:56

Note the standard sed syntax (as in POSIX, so supported by all conforming sed implementations around (GNU, OS/X, BSD, Solaris...)):

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

Or on one line:

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

(-expressions (and the contents of -files) are joined with newlines to make up the sed script sed interprets).

The -i option for in-place editing is also a GNU extension, some other implementations (like FreeBSD's) support -i '' for that.

Alternatively, for portability, you can use perl instead:

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

Or you could use ed or ex:

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file
查看更多
一夜七次
6楼-- · 2019-01-05 09:10

Try doing this using GNU sed:

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

if you want to substitute in-place, use

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

Output

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

Doc

  • see sed doc and search \a (append)
查看更多
Bombasti
7楼-- · 2019-01-05 09:12

Sed command that works on MacOS (at least, OS 10) and Unix alike (ie. doesn't require gnu sed like Gilles' (currently accepted) one does):

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

This works in bash and maybe other shells too that know the $'\n' evaluation quote style. Everything can be on one line and work in older/POSIX sed commands. If there might be multiple lines matching the CLIENTSCRIPT="foo" (or your equivalent) and you wish to only add the extra line the first time, you can rework it as follows:

sed -e '/^ *CLIENTSCRIPT="foo"/b ins' -e b -e ':ins' -e 'a\'$'\n''CLIENTSCRIPT2="hello"' -e ': done' -e 'n;b done' file

(this creates a loop after the line insertion code that just cycles through the rest of the file, never getting back to the first sed command again).

You might notice I added a '^ *' to the matching pattern in case that line shows up in a comment, say, or is indented. Its not 100% perfect but covers some other situations likely to be common. Adjust as required...

These two solutions also get round the problem (for the generic solution to adding a line) that if your new inserted line contains unescaped backslashes or ampersands they will be interpreted by sed and likely not come out the same, just like the \n is - eg. \0 would be the first line matched. Especially handy if you're adding a line that comes from a variable where you'd otherwise have to escape everything first using ${var//} before, or another sed statement etc.

This solution is a little less messy in scripts (that quoting and \n is not easy to read though), when you don't want to put the replacement text for the a command at the start of a line if say, in a function with indented lines. I've taken advantage that $'\n' is evaluated to a newline by the shell, its not in regular '\n' single-quoted values.

Its getting long enough though that I think perl/even awk might win due to being more readable.

查看更多
登录 后发表回答