How to replace the nth occurrence of a string using sed - sed

Is there any way to replace the nth occurrence of a string in a file using sed?
I'm using sed -i '0,/jack.*/ s//jill/' to replace the first occurrence.
How can i change it so that it replaces the nth occurrence?
My file contents the following lines:
first line
second line
third line
jack=1
fifth line
jack=
seventh line
I don't know the value after jack=, it can be anything or nothing.
I want to replace the 2nd occurrence of jack= and anything that follows it with jill.

First replace all the newlines with a unique character that does not occur anywhere else in your file (e.g. ^) using tr. You need to do this in order to create a single string for sed. Then pass it to sed and tell it to replace the nth occurrence of your string. Finally, pass the output back through tr to recreate the newlines.
For n=2, the command is:
$ tr '\n' '^' < file | sed 's/jack/jill/2' | tr '^' '\n'
first line
second line
third line
jack
fifth line
jill
seventh line
Update:
It can also be done with sed, WITHOUT changing the newlines first, using the following command:
$ sed ':a;N;$!ba;s/jack/jill/2' file
Alternatively, use awk:
$ awk '/jack/{c+=1}{if(c==2){sub("jack","jill",$0)};print}' file

Try this, sed ':a;N;$!ba;s/word1/word2/n' filename
Here, :a;N;$!ba is used to load the entire file into memory, line by line, so that sed can process the whole file in a single pass. The s/word1/word2/N substitution then replaces every Nth occurrence of word1 with word2.

Related

sed replace # with empty line

How do you replace a line that only has # with an empty line using sed?
I have tried to find on google but I haven't gotten anything.
File Content:
#test
another test
#
another test2
Expected result:
#test
another test
another test2
So, under expected result, after another test the line should be blank without the #.
Any help is greatly appreciated.
With regular expressions you can match for the beginning of a line with ^ and the end of a line with $. The s/regexp/replacement/ command will replace text that matches regexp with replacement.
This sed command gives the desired output:
sed 's/^#$//' < input.txt
On each line, sed looks for the start of a line, a # character, and then the end of a line, and replaces it with nothing. The newline character remains, however, so you are left with a blank line.
sed '/^#$//'
Anchor to beginning (^) and end ($) of line to match a whole line exactly.
Using sed
$ sed '/[[:alnum:]]/ ! s/#//' file
#test
another test
another test2
This might work for you (GNU sed):
sed '/^#$/g' file
If a line contains only #, replace it by a blank line.
Alternatives:
sed 's/^#$//' file
or
sed '/^#$/c\\' file

How to replace the nth occurrence of a sttring in a file using sed [duplicate]

This question already has answers here:
How to replace the nth occurrence of a string using sed
(2 answers)
Closed 8 years ago.
Is there any way to replace the nth occurrence of a string in a file using sed?
How can i change it so that it replaces the nth occurrence?
My file contents the following lines:
first line
second line
third line
jack
fifth line
jack
seventh line
consider a variable var = jill.
I want to replace the 2nd occurrence of jack with value of variable $var.
This might work for you (GNU sed):
sed ':a;$!{N;ba};s/jack/'"$var"'/2' file
This slurps the file into memory and then substitutes the second occurence of jack for $var.
EDIT:
:a is a place holder for a b command, it tell sed to break/jump to position i.e ba jump to :a.
$! is an address. $ means end of file and ! means not. Put together this means any address which is not-the-end-of-file.
{...} groups the commands between the braces.
N appends a newline and then the next line to the pattern space except when there are no more lines when it passes sed to just passed the last command (if the -n is not set it will print what ever is in the pattern space, if -n is set it will just end processing).
s/jack/'$var"'/2 this is a sed substitution command and replaces the second occurrence of jack by the contents of $var. N.B. the '...' which effectively breaks out sed commands into the underlying shell and then back again allowing the shell variable to be interpolated.
In summary the whole file is slurped into memory and the second occurrence of jack is replaced by the contents of $var.
In most cases this could by replaced by:
sed -z 's/jack/'"$var"'/2' file
Here is an awk version if you like to use awk
awk -v c="$var" '/jack/ && ++a==2 {sub(/jack/,c)}1' file
first line
second line
third line
jack
fifth line
jill
seventh line

how to replace a line based on variable match using sed

Is it possible to use sed to replace some text based on the matching of a condition at the beginning of the text... For example, for the following file, I only want to replace the word 'guest' to 'unwanted-guest' only for the line that begins with the pattern '
541ce0a0c3b4f843ec000001' which is a variable.
541ce0a0c3b4f843ec000001:x:1000:1000:OpenShift guest:/var/lib/openshift/541ce0a0c3b4f843ec000001:/usr/bin/oo-trap-user
541ce468c3b4f843ec000029:x:1001:1001:OpenShift guest:/var/lib/openshift/541ce468c3b4f843ec000029:/usr/bin/oo-trap-user
Try:
sed '/^541ce0a0c3b4f843ec000001/ s/guest/unwanted-guest/'
We have placed a condition in front of the usual sed substitute command. The condition is:
/^541ce0a0c3b4f843ec000001/
This condition limits sed to considering only lines that start with 541ce0a0c3b4f843ec000001 (The caret ^ means must-be-at-the-beginning-of-a-line). The substitute command is:
s/guest/unwanted-guest/
This replaces the first occurrence of guest on the line with unwanted-guest.
Example
Applying this command to your sample input (placed in a file named file):
$ sed '/^541ce0a0c3b4f843ec000001/ s/guest/unwanted-guest/' file
541ce0a0c3b4f843ec000001:x:1000:1000:OpenShift unwanted-guest:/var/lib/openshift/541ce0a0c3b4f843ec000001:/usr/bin/oo-trap-user
541ce468c3b4f843ec000029:x:1001:1001:OpenShift guest:/var/lib/openshift/541ce468c3b4f843ec000029:/usr/bin/oo-trap-user
Using with a variable
$ id=541ce0a0c3b4f843ec000001
$ sed "/^$id/ s/guest/unwanted-guest/" file
541ce0a0c3b4f843ec000001:x:1000:1000:OpenShift unwanted-guest:/var/lib/openshift/541ce0a0c3b4f843ec000001:/usr/bin/oo-trap-user
541ce468c3b4f843ec000029:x:1001:1001:OpenShift guest:/var/lib/openshift/541ce468c3b4f843ec000029:/usr/bin/oo-trap-user

sed: replace pattern only if followed by empty line

I need to replace a pattern in a file, only if it is followed by an empty line. Suppose I have following file:
test
test
test
...
the following command would replace all occurrences of test with xxx
cat file | sed 's/test/xxx/g'
but I need to only replace test if next line is empty. I have tried matching a hex code, but that doesn ot work:
cat file | sed 's/test\x0a/xxx/g'
The desired output should look like this:
test
xxx
xxx
...
Suggested solutions for sed, perl and awk:
sed
sed -rn '1h;1!H;${g;s/test([^\n]*\n\n)/xxx\1/g;p;}' file
I got the idea from sed multiline search and replace. Basically slurp the entire file into sed's hold space and do global replacement on the whole chunk at once.
perl
$ perl -00 -pe 's/test(?=[^\n]*\n\n)$/xxx/m' file
-00 triggers paragraph mode which makes perl read chunks separated by one or several empty lines (just what OP is looking for). Positive look ahead (?=) to anchor substitution to the last line of the chunk.
Caveat: -00 will squash multiple empty lines into single empty lines.
awk
$ awk 'NR==1 {l=$0; next}
/^$/ {gsub(/test/,"xxx", l)}
{print l; l=$0}
END {print l}' file
Basically store previous line in l, substitute pattern in l if current line is empty. Print l. Finally print the very last line.
Output in all three cases
test
xxx
xxx
...
This might work for you (GNU sed):
sed -r '$!N;s/test(\n\s*)$/xxx\1/;P;D' file
Keep a window of 2 lines throughout the length of the file and if the second line is empty and the first line contains the pattern then make a substitution.
Using sed
sed -r ':a;$!{N;ba};s/test([^\n]*\n(\n|$))/xxx\1/g'
explanation
:a # set label a
$ !{ # if not end of file
N # Add a newline to the pattern space, then append the next line of input to the pattern space
b a # Unconditionally branch to label. The label may be omitted, in which case the next cycle is started.
}
# simply, above command :a;$!{N;ba} is used to read the whole file into pattern.
s/test([^\n]*\n(\n|$))/xxx\1/g # replace the key word if next line is empty (\n\n) or end of line ($)

SED inserting a blank line below a line

I want to add a black line below a line ending in a period.
I have sed '/ REGEX goes here/G' I'm not sure how to replace the regex to except a period as expression to look for.
I want to add a blank line below each sentence here's an example of some text I would want to use the sed shell script on.
Line one.
The second line.
The third.
This is line four.
five.
This is the sixth sentence.
This is line seven.
Eighth and last.
Try following sed
sed 's/\.$/.\n/' file
EDIT (after comments of #Jotne)
If you have any spaces after . at the end of line, adding \s* would be safe.
sed 's/\.\s*$/.\n/' file
I'm not sure how to replace the regex to except a period as expression
to look for.
You can say:
sed '/\.$/G' filename
Escape the . so as to match a literal .; the anchor $ ensures that the matched . was at the end of line.