Strictly speaking, the POSIX specification for sed
requires a newline after a\
:
[1addr]a\
text
Write text to standard output as described previously.
This makes writing one-liners a bit of a pain, which is probably the reason for the following GNU extension to the a
, i
, and c
commands:
As a GNU extension, if between the a
and the newline there is other than a whitespace-\
sequence, then the text of this line, starting at the first non-whitespace character after the a
, is taken as the first line of the text block. (This enables a simplification in scripting a one-line add.) This extension also works with the i
and c
commands.
Thus, to be portable with your sed
syntax, you will need to include a newline after the a\
somehow. The easiest way is to just insert a quoted newline:
$ sed -e 'a\
> text'
(where $
and >
are shell prompts). If you find that a pain, bash
[1] has the $' '
quoting syntax for inserting C-style escapes, so just use
sed -e 'a\'$'\n''text'
[1] and mksh (r39b+) and some non-bash bourne shells (e.g., /bin/sh in FreeBSD 9+)
There are four ways to include the single quote that you need.
One cannot escape a single-quotes string within a single-quoted string. However, one can end the quoted string, insert an escaped single-quote, and then start a new single-quoted string.
Thus, to put a single quote in the middle of 'ab'
, use: 'a'\''b'
. Or, using the sed command that you need:
$ sed -r 's/,([^ ),]+)/,'\''\1'\''/g; s/,,/,'\'\'',/g' file
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
The second way is to use a double-quoted string, in which case the single-quote can be inserted easily:
$ sed -r "s/,([^ ),]+)/,'\1'/g; s/,,/,'',/g" file
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
This issue with double-quoted strings is that the shell does processing on them. Here, though, there are no shell-active characters, so it is easy.
The third method is to use a hex escape as PM2Ring demonstrates.
The fourth way, suggested in the comments by Jonathan Leffler, is to place the sed
commands in a separate file:
$ cat script.sed
s/,([^ ),]+)/,'\1'/g
s/,,/,'',/g
$ sed -rf script.sed file
INSERT INTO radcheck(id, username, attribute, op, value) VALUES (,'','00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
This way has the strong advantage that sed
reads the commands directly without any interference from the shell. Consequently, this completely avoids the need to escape shell-active characters and allows the commands to be entered in pure sed
syntax.
How the sed
solution works
The trick is to put single quotes around the comma-separated strings that you want but not around the others. Based on the single example that you gave, here is one approach:
s/,([^ ),]+)/,'\1'/g
This looks for one or more non-space, non-comma, and non-close-parens characters which follow a comma. These characters are placed inside single quotes.
s/,,/,'',/g
This looks for consecutive commas and places a two single-quotes between them.
OSX and other BSD platforms
To avoid extra backslashes, the above sed
expressions use extended regular expressions. With GNU, these are invoked as -r
but, with BSD, they are invoked with -E
. Also, some non-GNU sed
do not accept multiple commands separated with semicolons. Thus, on OSX, try:
sed -E -e "s/,([^ ),]+)/,'\1'/g" -e "s/,,/,'',/g" file
Addendum: Matching a MAC address
From the comments, we have the following input;
$ cat file3
INSERT INTO radcheck(username, attribute, op, value) VALUES (00:23:32:c2:a9:e8,'Auth-Type',':=','Accept');
And, we want to put single-quotes around the MAC address that follows the open-parens. To do that:
$ sed -r "s/\(([[:xdigit:]:]+)/('\1'/" file3
INSERT INTO radcheck(username, attribute, op, value) VALUES ('00:23:32:c2:a9:e8','Auth-Type',':=','Accept');
In any locale, [:xdigit:]
will match any hexadecimal digit. Thus, ([[:xdigit:]:]+)
will match a MAC address (hex digit or colon).
Best Answer
Use
sed
's insert (i
) option which will insert the text in the preceding line.Question author's update:
To make it edit the file in place - with GNU
sed
- I had to add the-i
option:Also syntax
For non-GNU sed
You need to hit the return key immediately after the backslash
1i\
and afterfirst_line_text
:Also note that some non-GNU
sed
implementations (for example the one on macOS) require an argument for the-i
flag (use-i ''
to get the same effect as with GNUsed
).For
sed
implementations that does not support-i
at all, run without this option but redirect the output to a new file. Then replace the old file with the newly created file.