Add a line after an occurrence - bash

The variables are
espejo=u456789
usuario=u123456
grupo=unixgr
I want to add after the line occurrence of variable $espejo, the text in variables $usuario and $grupo:
cp $DIRECTORY/usu.txt $DIRECTORY/usu.txt.`date '+%F'`
sed "/${espejo}/a\ ${usuario} ${grupo}" $DIRECTORY/usu.txt.`date '+%F'` > $DIRECTORY/usu.txt
I got this error during the execution:
sed: 0602-404 Function /u456789/a\u123456 unixgr cannot be parsed.
I don't know what is wrong.

Try the following:
sed "/${espejo}/a\
${usuario} ${grupo}" $DIRECTORIO/usu.txt.`date '+%F'` > $DIRECTORIO/usu.txt
Note that after the backslash on first line there is no any other symbols except new line.

Try this:
sed "s:${espejo}:${espejo}\n${usuario} ${grupo}:" $DIRECTORIO/usu.txt.`date '+%F'` > $DIRECTORIO/usu.txt
If the above just adds n instead of newline, try this:
sed "s:${espejo}:${espejo}\
${usuario} ${grupo}:" $DIRECTORIO/usu.txt.`date '+%F'` > $DIRECTORIO/usu.txt
This will append the new variable in new line. I guess you are facing the problem since ${espejo} contains / character in it.

This might work for you (GNU sed):
sed "/$espejo/r /dev/stdin" file <<<" ${usuario} ${grupo}"

Related

Not able to add a line of text after pattern using sed in OSX

I'm trying to add a line in a file afile.xyz using my script. This is what I've done so far using sed:
n="$(grep ".method" "$m" | grep "onCreate(Landroid/os/Bundle;)V")"
sed -i '' -e '/$n/ a\
"test", /Users/username/Documents/afile.xyz
I'm getting the error:
"onCreate\(\Landroid\/ ...": bad flag in substitute command: 'g'
How do I solve this? Please do help. Thanks.
Edit: Content of n
method protected onCreate(Landroid/os/Bundle;)V
2 problems:
because the sed body is in single quotes, the variable $n will not be expanded,
the regular expression in $n contains the / dilimiters.
Try this:
n=$(...)
nn=${n//\//\\/} # escape all slashes
sed -i '' '/'"${nn}"'/ a ...
The single-quoted sed body is interrupted to append the double quoted shell variable.
You can also use a different delimiter for the RE:
sed -i '' -e "\#$n# a\\
\"test\"" /Users/username/Documents/afile.xyz

How to add a character to the end of a line, when a find and replace is done to the beginning?

I am creating a simple script that converts a custom markup to TeX macros:
? What are four kinds of animals?
- elephants
- tigers
- bears
- fish
e
This becomes:
\QUESTION{What are four kinds of animals?}{
\ANSWER{elephants}
\ANSWER{tigers}
\ANSWER{bears}
\ANSWER{fish}
}
I have used a simple syntax to replace the items at the front:
sed 's#^? #\\QUESTION{#' file > temp1
sed 's#^\- #\\ANSWER{#' temp1 > temp2
sed 's#^e #\}{#' temp2 > temp3
How do I get it to also add the }{ to the end when "?" is found at the beginning, and add } to the end when "-" is found at the beginning of the line?
Match the whole line instead of its beginning, and use a replacement pattern referencing the content of the line :
sed -e 's#^? \(.*\)#\\QUESTION{\1}{' -e 's#^- \(.*\)#\\ANSWER{\1}#' -e 's#^e#}#'
In this command \(...\) are capturing groups and \1 refers to their content.
I also took the liberty of regrouping your multiple substitutions in a single sed command.
Like this:
sed -E 's/^(\? )(.*)/\\QUESTION{\2}{/;t;s/- (.*)/\ANSWER{\1}/;t;s/e/}/' file
Explanation:
s/^(\? )(.*)/\\QUESTION{\2}{/ Handle lines starting with ?
t means not further actions if the above s command replaced something
s/- (.*)/\ANSWER{\1}/ Handle lines starting with -
t means not further actions if the above s command replaced something
s/^e/}/ Handle lines starting with e.
You can "speed it up" a bit by reordering the commands by the complexity of the search pattern, like this:
sed -E 's/e/}/;t;s/- (.*)/\ANSWER{\1}/;t;s/^(\? )(.*)/\\QUESTION{\2}{/;' file
But yeah, probably micro-optimization.
You can try this sed too :
sed '/^- /s//\\ANSWER{/;/^e/s///;s/$/}/;/^? /{s//\\QUESTION{/;s/$/{/}' infile
sed '
/^- /s//\\ANSWER{/ # line with -
/^e/s/// # line with e
s/$/}/ # add } at the end of each line
/^? / { # line with ?
s//\\QUESTION{/
s/$/{/
}
' infile

sed: Replacing a range of text with contents of a file

There are many examples here and elsewhere on the interwebs for using sed's 'r' to replace a pattern, but it does not seem to work on a range, but maybe I'm just not holding it right.
The following works as expected, deleting BEGIN PATTERN and replacing it with the contents of /tmp/somefile.
sed -n "/BEGIN PATTERN/{ r /tmp/somefile d }" TARGET_FILE
This, however, only replaces END_PATTERN with the contents of /tmp/somefile.
sed -n "/BEGIN PATTERN/,/END PATTERN/ { r /tmp/somefile d }" TARGET_FILE
I suppose I could try perl or awk to do this as well, but it seems like sed should be able to do this.
I believe that this does what you want:
sed $'/BEGIN PATTERN/r somefile\n /BEGIN PATTERN/,/END PATTERN/d' file
Or:
sed -e '/BEGIN PATTERN/r somefile' -e '/BEGIN PATTERN/,/END PATTERN/d' file
How it works
/BEGIN PATTERN/r somefile
Whenever BEGIN PATTERN is found, this inserts the contents of somefile.
/BEGIN PATTERN/,/END PATTERN/d
Whenever we are in the range from a line with /BEGIN PATTERN/ to a line with /END PATTERN/, we delete (d) the contains of the pattern buffer.
Example
Let's consider these two test files:
$ cat file
prelude
BEGIN PATTERN
middle
END PATTERN
afterthought
and:
$ cat somefile
This is
New.
Our command produces:
$ sed $'/BEGIN PATTERN/r somefile\n /BEGIN PATTERN/,/END PATTERN/d' file
prelude
This is
New.
afterthought
This might work for you (GNU sed):
sed -e '/BEGIN PATTERN/,/END PATTERN/{/END PATTERN/!d;r somefile' -e 'd}' file
John1024's answer works if BEGIN PATTERN and END PATTERN are different. If this is not the case, the following works:
sed $'/PATTERN/,/PATTERN/d; 1,/PATTERN/ { /PATTERN/r somefile\n }' file
By preserving the pattern:
sed $'/PATTERN/,/PATTERN/ { /PATTERN/!d; }; 1,/PATTERN/ { /PATTERN/r somefile\n }' file
This solution can yield false positives if the pattern is not paired as potong pointed out.

sed with replacement part given as input from command line

I am trying to pass command line argument as the replacement part to sed command. But $1 doesn't work for me.
For example I unsuccesfully tried
function changeversion() {
sed -i 's/[0-9]\+/$1/g' file.xml;
}
which only replaced all numbers in file with '$1' text.
How can I fix it?
I think you need to put the expression in double qoutes to get variable substitution
function changeversion() {
sed -i "s/[0-9]\+/$1/g" file.xml;
}

How do I insert a newline/linebreak after a line using sed

It took me a while to figure out how to do this, so posting in case anyone else is looking for the same.
For adding a newline after a pattern, you can also say:
sed '/pattern/{G;}' filename
Quoting GNU sed manual:
G
Append a newline to the contents of the pattern space, and then append the contents of the hold space to that of the pattern space.
EDIT:
Incidentally, this happens to be covered in sed one liners:
# insert a blank line below every line which matches "regex"
sed '/regex/G'
This sed command:
sed -i '' '/pid = run/ a\
\
' file.txt
Finds the line with: pid = run
file.txt before
; Note: the default prefix is /usr/local/var
; Default Value: none
;pid = run/php-fpm.pid
; Error log file
and adds a linebreak after that line inside file.txt
file.txt after
; Note: the default prefix is /usr/local/var
; Default Value: none
;pid = run/php-fpm.pid
; Error log file
Or if you want to add text and a linebreak:
sed -i '/pid = run/ a\
new line of text\
' file.txt
file.txt after
; Note: the default prefix is /usr/local/var
; Default Value: none
;pid = run/php-fpm.pid
new line of text
; Error log file
A simple substitution works well:
sed 's/pattern.*$/&\n/'
Example :
$ printf "Hi\nBye\n" | sed 's/H.*$/&\nJohn/'
Hi
John
Bye
To be standard compliant, replace \n by backslash newline :
$ printf "Hi\nBye\n" | sed 's/H.*$/&\
> John/'
Hi
John
Bye
sed '/pattern/a\\r' file name
It will add a return after the pattern while g will replace the pattern with a blank line.
If a new line (blank) has to be added at end of the file use this:
sed '$a\\r' file name
Another possibility, e.g. if You don't have an empty hold register, could be:
sed '/pattern/{p;s/.*//}' file
Explanation:
/pattern/{...} = apply sequence of commands, if line with pattern found,
p = print the current line,
; = separator between commands,
s/.*// = replace anything with nothing in the pattern register,
then automatically print the empty pattern register as additional line)
The easiest option -->
sed 'i\
' filename

Resources