Substituting a single line with multiple lines of text - linux

In Linux what command can I use to replace a single line of text with new multiple lines? I want to look for a keyword on a line and delete this line and replace it with multiple new lines. So in the text shown below I want to search for the line that contains "keyword" and replace the entire line with 3 new lines of text as shown.
For example replacing the line containing the keyword,
This is Line 1
This is Line 2 that has keyword
This is Line 3
changed to this:
This is Line 1
Inserted is new first line
Inserted is new second line
Inserted is new third line
This is Line 3

$ sed '/keyword/c\
> Inserted is new first line\
> Inserted is new second line\
> Inserted is new third line' input.txt
This is Line 1
Inserted is new first line
Inserted is new second line
Inserted is new third line
This is Line 3
$ and > are bash prompt

Create a file, script.sed, containing:
/keyword/{i\
Inserted is new first line\
Inserted is new second line\
Inserted is new third line
d
}
Apply it to your data:
sed -f script.sed your_data
There are numerous variations on how to do it, using the c and a commands instead of i and/or d, but this is reasonably clean. It finds the keyword, inserts three lines of data, and then deletes the line containing the keyword. (The c command does that all, but I didn't remember that it existed, and the a command appends the text and is essentially synonymous with i in this context.)

you can do it using shell builtins too:
STRING1_WITH_MULTIPLE_LINES="your
text
here"
STRING2_WITH_MULTIPLE_LINES="more
text"
OUTPUT=""
while read LINE || [ "$LINE" ]; do
case "$LINE" in
"Entire line matches this")OUTPUT="$OUTPUT$STRING1_WITH_MULTIPLE_LINES
";;
*"line matches this with extra before and/or after"*)OUTPUT="$OUTPUT$STRING2_WITH_MULTIPLE_LINES
";;
*)OUTPUT="$OUTPUT$LINE
";;
esac
done < file
echo "$OUTPUT" >file

Related

How to Remove the whole line with a matching pattern exists only in the column range 75 to 104

I have a file which contains data in the below form.
507425B30 171013D248900022 4057-ACCR PROPERTY TAX
00000000257910+00000000000000+00000000257910+00000000000000+00000000000000+
507425B30 171013C249999092 1071-DO NOT USE
00000000000000+00000000000000+00000000000000+00000000031940+00000000000000+
Now i have to delete the lines which contains the pattern like
00000000000000+00000000000000+ and the tricky part is that we have to delete
the line only when it comes in the 1st occurrence. There will be scenarios
like the first record in the above where the pattern came at the last and it
should not delete the line from the file. I tried using the below command
but it is deleting the line when it finds that pattern in the last which
shouldn't be the case.
sed '/00000000000000+00000000000000+/d' file
I have written the below code to fix this issue. But it seems it is going to the Infinite loop. Can you help where i am going wrong?
while read line
do
x=`cat $Line | cut -c 75-104`
echo $x
if [ $x -eq "00000000000000+00000000000000+" ]
then
sed '/00000000000000+00000000000000+/d' $File > File.dat
fi
done < $File
This will remove every line of 'file' that begin with 14 zeros and a plus char two times.
sed -i '/^[0]\{14\}+[0]\{14\}+/d' file

Replace string with another depending on another line

I need to write a script, that goes through a bunch of text files and replaces a certain string with another. The other one is located two lines below the certain string. Like this:
some text
this is the first line (helloWorld).
this is the second line.
This is the third line (patternxxx).
more text
And I want this:
some text
this is the first line (helloxxxWorld).
this is the second line.
This is the third line (patternxxx).
more text
I'm under Linux.
awk '
BEGIN { mr=3 }
/helloWorld/{ mr=0; gsub("helloWorld","helloxxxWorld");print; };
mr==2 { gsub("pattern", "patternxxx");}
mr++
'
test:
$ cat file
some text
this is the first line (helloWorld).
this is the second line.
This is the third line (pattern).
more text
some text
this is the first line (helloWorld).
this is the second line.
this is the second line.
This is the third line (pattern).
more text
$ awk '
BEGIN { mr=3 }
/helloWorld/{ mr=0; gsub("helloWorld","helloxxxWorld");print; };
mr==2 { gsub("pattern", "patternxxx");}
mr++
' file
some text
this is the first line (helloxxxWorld).
this is the second line.
This is the third line (patternxxx).
more text
some text
this is the first line (helloxxxWorld).
this is the second line.
this is the second line.
This is the third line (pattern).
more text
You can achieve this using sed, see below command. this will permanently make changes in the files.
sed -i 's/helloWorld/helloxxxWorld/g' file1 file2 ...filen
You can loop files one by one also.
for file in `ls`;
do
sed -i 's/helloWorld/helloxxxWorld/g' $file;
echo "$file completed";
done
make sure you have backups for the files.
This might work for you (GNU sed):
sed -ri '1N;N;s/(hello)(World.*\n.*\n.*pattern(xxx))/\1\3\2/;P;D' file1 file2 ...
Open a three line window in the file and pattern match on the first and third lines throughout the file.

delete a line after a pattern only if it is blank using sed or awk

I want to delete a blank line only if this one is after the line of my pattern using sed or awk
for example if I have
G
O TO P999-ERREUR
END-IF.
the pattern in this case is G
I want to have this output
G
O TO P999-ERREUR
END-IF.
This will do the trick:
$ awk -v n=-2 'NR==n+1 && !NF{next} /G/ {n=NR}1' file
G
O TO P999-ERREUR
END-IF.
Explanation:
-v n=-2 # Set n=-2 before the script is run to avoid not printing the first line
NR == n+1 # If the current line number is equal to the matching line + 1
&& !NF # And the line is empty
{next} # Skip the line (don't print it)
/G/ # The regular expression to match
{n = NR} # Save the current line number in the variable n
1 # Truthy value used a shorthand to print every (non skipped) line
Using sed
sed '/GG/{N;s/\n$//}' file
If it sees GG, gets the next line, removes the newline between them if the next line is empty.
Note this will only remove one blank line after, and the line must be blank i.e not spaces or tabs.
This might work for you (GNU sed):
sed -r 'N;s/(G.*)\n\s*$/\1/;P;D' file
Keep a moving window of two lines throughout the length of the file and remove a newline (and any whitespace) if it follows the intended pattern.
Using ex (edit in-place):
ex +'/G/j' -cwq foo.txt
or print to the standard output (from file or stdin):
ex -s +'/GG/j|%p|q!' file_or_/dev/stdin
where:
/GG/j - joins the next line when the pattern is found
%p - prints the buffer
q! - quits
For conditional checking (if there is a blank line), try:
ex -s +'%s/^\(G\)\n/\1/' +'%p|q!' file_or_/dev/stdin

Command to insert lines before first match

I have file with the below info
testing
testing
testing
I want to insert a word(tested) before the first testing word using sed or any linux command
need to get output like
tested
testing
testing
testing
Thanks
For lines consisting of "testing" exactly:
sed '0,/^testing$/s/^testing$/tested\n&/' file
For lines containing "testing":
sed '0,/.*testing.*/s/.*testing.*/tested\n&/' file
For Lines Starting with "testing"
sed '0,/^testing.*/s/^testing.*/tested\n&/' file
For lines ending with "testing":
sed '0,/.*testing$/s/.*testing$/tested\n&/' file
To update the content of the file with the result add "-i", example:
sed -i '0,/testing/s/testing/tested\n&/' file
To provide an awk-based alternative that is easier to understand:
awk '!found && /testing/ { print "tested"; found=1 } 1' file
found is used to keep track of whether the first instance of testing has been found (variable found, as any Awk variable, defaults to 0, i.e., false in a Boolean context).
/testing/ therefore matches the first line containing testing, and processes the associated block:
{ print "tested"; found=1 } prints the desired text and sets the flag that the first testing line has been found
1 is a common shorthand for { print }, i.e., simply printing the current input line as is.
This might work for you (GNU sed):
sed -e '/testing/{itested' -e ':a;n;ba}' file
Insert tested before the first match of testing and then use a loop to read/print the remainder of the file.
Or use the GNU specific:
sed '0,/testing/itested' file
Consider file:
apple
banana
bar TEST qux
TEST foo
baz TEST
TEST
TEST
Insert a line before the first occurrence of a line consisting solely of the string 'TEST':
sed '0,/^TEST$/s//INSERTED LINE\n&/' <file
Result:
apple
banana
bar TEST qux
TEST foo
baz TEST
INSERTED LINE
TEST
TEST
0,/^TEST$ is an address range. This range begins at the first line of input and extends until a line beginning and ending with TEST is reached. The use of a range restricts the region of applicability of the following command, a substitution command in our case.
A note about the meaning of //:
The empty regular expression ‘//’ repeats the last regular expression match
– https://www.gnu.org/software/sed/manual/html_node/Regexp-Addresses.html
A note about the meaning of the ampersand, &, used in the replacement portion of the s command:
the replacement can contain unescaped & characters which reference the whole matched portion of the pattern space
– https://www.gnu.org/software/sed/manual/html_node/The-_0022s_0022-Command.html
For completeness, here's three additional cases to consider...
Insert a line before the first occurrence of a line containing 'TEST':
sed '0,/.*TEST/s//INSERTED LINE\n&/' <file
Insert a line before the first occurrence of a line beginning with 'TEST':
sed '0,/^TEST/s//INSERTED LINE\n&/' <file
Insert a line before the first occurrence of a line ending with 'TEST':
sed '0,/.*TEST$/s//INSERTED LINE\n&/' <file

sed to insert on first match only

UPDATED:
Using sed, how can I insert (NOT SUBSTITUTE) a new line on only the first match of keyword for each file.
Currently I have the following but this inserts for every line containing Matched Keyword and I want it to only insert the New Inserted Line for only the first match found in the file:
sed -ie '/Matched Keyword/ i\New Inserted Line' *.*
For example:
Myfile.txt:
Line 1
Line 2
Line 3
This line contains the Matched Keyword and other stuff
Line 4
This line contains the Matched Keyword and other stuff
Line 6
changed to:
Line 1
Line 2
Line 3
New Inserted Line
This line contains the Matched Keyword and other stuff
Line 4
This line contains the Matched Keyword and other stuff
Line 6
You can sort of do this in GNU sed:
sed '0,/Matched Keyword/s//New Inserted Line\n&/'
But it's not portable. Since portability is good, here it is in awk:
awk '/Matched Keyword/ && !x {print "Text line to insert"; x=1} 1' inputFile
Or, if you want to pass a variable to print:
awk -v "var=$var" '/Matched Keyword/ && !x {print var; x=1} 1' inputFile
These both insert the text line before the first occurrence of the keyword, on a line by itself, per your example.
Remember that with both sed and awk, the matched keyword is a regular expression, not just a keyword.
UPDATE:
Since this question is also tagged bash, here's a simple solution that is pure bash and doesn't required sed:
#!/bin/bash
n=0
while read line; do
if [[ "$line" =~ 'Matched Keyword' && $n = 0 ]]; then
echo "New Inserted Line"
n=1
fi
echo "$line"
done
As it stands, this as a pipe. You can easily wrap it in something that acts on files instead.
If you want one with sed*:
sed '0,/Matched Keyword/s//Matched Keyword\nNew Inserted Line/' myfile.txt
*only works with GNU sed
This might work for you:
sed -i -e '/Matched Keyword/{i\New Inserted Line' -e ':a;n;ba}' file
You're nearly there! Just create a loop to read from the Matched Keyword to the end of the file.
After inserting a line, the remainder of the file can be printed out by:
Introducing a loop place holder :a (here a is an arbitrary name).
Print the current line and fetch the next into the pattern space with the ncommand.
Redirect control back using the ba command which is essentially a goto to the a place holder. The end-of-file condition is naturally taken care of by the n command which terminates any further sed commands if it tries to read passed the end-of-file.
With a little help from bash, a true one liner can be achieved:
sed $'/Matched Keyword/{iNew Inserted Line\n:a;n;ba}' file
Alternative:
sed 'x;/./{x;b};x;/Matched Keyword/h;//iNew Inserted Line' file
This uses the Matched Keyword as a flag in the hold space and once it has been set any processing is curtailed by bailing out immediately.
If you want to append a line after first match only, use AWK instead of SED as below
awk '{print} /Matched Keyword/ && !n {print "New Inserted Line"; n++}' myfile.txt
Output:
Line 1
Line 2
Line 3
This line contains the Matched Keyword and other stuff
New Inserted Line
Line 4
This line contains the Matched Keyword and other stuff
Line 6

Resources