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
Related
Newbie to unix/shell/bash. I have a file name CellSite whose 6th line is as below:
btsName = "RV74XC038",
I want to extract the string from 6th line that is between double quotes (i.e.RV74XC038) and save it to a variable. Please note that the 6th line starts with 4 blank spaces. And this string would vary from file. So I am looking for a solution that would extract a string from 6th line between the double quotes.
I tried below. But does not work.
str2 = sed '6{ s/^btsName = \([^ ]*\) *$/\1/;q } ;d' CellSite;
Any help is much appreciated. TIA.
sed is a stream editor.
For just parsing files, you want to look into awk. Something like this:
awk -F \" '/btsName/ { print $2 }' CellSite
Where:
-F defines a "field separator", in your case the quotation marks "
the entire script consists of:
/btsName/ act only on lines that contain the regex "btsName"
from that line print out the second field; the first field will be everything before the first quotation marks, second field will be everything from the first quotes to the second quotes, third field will be everything after the second quotes
parse through the file named "CellSite"
There are possibly better alternatives, but you would have to show the rest of your file.
Using sed
$ str2=$(sed '6s/[^"]*"\([^"]*\).*/\1/' CellSite)
$ echo "$str2"
RV74XC038
You can use the following awk solution:
btsName=$(awk -F\" 'NR==6{print $2; exit}' CellSite)
Basically, get to the sixth line (NR==6), print the second field value (" is used to split records (lines) into fields) and then exit.
See the online demo:
#!/bin/bash
CellSite='Line 1
Line 2
Line 3
btsName = "NO74NO038",
Line 5
btsName = "RV74XC038","
Line 7
btsName = "no11no000",
'
btsName=$(awk -F\" 'NR==6{print $2; exit}' <<< "$CellSite")
echo "$btsName" # => RV74XC038
This might work for you (GNU sed):
var=$(sed -En '6s/.*"(.*)".*/\1/p;6q' file)
Simplify regexs and turn off implicit printing.
Focus on the 6th line only and print the value between double quotes, then quit.
Bash interpolates the sed invocation by means of the $(...) and the value extracted defines the variable var.
I am trying to trim the data above the line from a file, where line containing some string by passing variable to it
varfile=$(cat variable.txt)
echo "$varfile"
if [ -z "$varfile" ]; then
echo "null"
else
echo "data"
sed "1,/$varfile/d" fileee.txt
fi
Here I am taking a string from variable.txt file and trying to find that text in fileee.txt file and removing all the data above the line
EX: variable.txt has 3
I am finding 3 in fileee.txt and removing data above three
INPUT:
1
2
3
4
OUTPUT:
3
4
I suppose the issue here is that you want to remove all lines before the match, but not the matching line itself?
One way, with GNU sed, is to explicitly add a print for the matching line first:
pattrn=3
seq 1 4 | sed -e "/$pattrn/p;1,/$pattrn/d"
Though this will duplicate any further lines that match the pattern.
Better, invert the sense of the match:
seq 1 4 | sed -ne "/$pattrn/,\$p"
That is, don't print by default (-n), but print (p) anything from a match to the end ($, escaped because of the double-quoted string)
Even better would be to use awk:
pattrn=3
seq 1 4 | awk -vpat="$pattrn" '$0 ~ pat {p=1} p'
This sets a flag on the line where the whole line ($0) matches the pattern (~ is a regex match), then prints the lines whenever that flag is set.
The awk solution is also better in that special characters in the pattern don't cause issues (at least not as many); in the sed case, if the pattern contains a slash /, it will terminate the regex in the sed code, and cause syntax errors or allow for code injection.
I used seq from GNU coreutils here only to make up the sequence of numbers for input.
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.
Hello I need oneliner to insert character after Nth occurrence of delimiter on 2nd line in unix; The criteria are these.
Find position of nth occurrence of the delimiter.
Insert character after the nth occurrence.
This is on the 2nd line only.
Note: I am doing this in Linux.
With awk :
INPUT FILE
1 foo bar base
2 foo bar base
CODE
awk 'NR==2{$2=$2"X"; print}' file
you can specify a delimiter with -F
NR to specify the line we work on
$2 is the 2th value separated by space (in this case)
$2=$2"X" is a concatenation
print alone print the entire line
OUTPUT
2 fooX bar base
Suppose we have the input file:
$ cat file
1 foo bar base
2 foo bar base
To insert the character X after the 3rd occurrence of the delimiter space, use:
$ sed -r '2 s/([^ ]* ){3}/&X/' file
1 foo bar base
2 foo bar Xbase
To make the change to the file in place, use sed's -i option:
sed -i -r '2 s/([^ ]* ){3}/&X/' file
How it works
Consider the sed command:
2 s/([^ ]* ){3}/&X/
The initial 2 instructs sed to apply this command only to the second line.
We are using the s or substitute command. This command has the form s/old/new/ where old and new are:
old is the regular expression ([^ ]* ){3}. This matches everything up to and including the third occurrence of space.
new is the replacement text, &X. The ampersand refers to what we matched in old, which is all the line up to and including the third space. The X is the new character that we are inserting.
This might work for you (GNU sed):
sed '2s/X/&Y/3' file
This inserts Y after the third occurence of X on the second line 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