Using regex for address range - sed

I have the following file:
$ cat file
> First line
> Second line
> Third line
> Fourth and last line
> First line
> Second line
> Third line
> Fourth and last line
I want to print the first 3 lines, easy:
$ sed -n '1,3p' file
> First line
> Second line
> Third line
Now I want to print from the occurrence First to the occurrence Third:
$ sed -n '/First/,/Third/p' file
> First line
> Second line
> Third line
> First line
> Second line
> Third line
Ah! Not quite what I wanted, I want only the first occurrence of the matched pattern range. How can I do that when I have regex' as my addresses?

Append the end-pattern as a quit condition:
sed -n '/First/,/Third/p; /Third/q' file
Output:
> First line
> Second line
> Third line

You can try this sed:
sed -n '/First/{:loop; $!N; /Third/{p;q}; b loop;}' file

I believe awk may help you to do this
awk '/First/{found=1} found{print; if(/Third/) exit}' file

You can do like this with awk
awk '!f; /Third/ {f=1}' file
> First line
> Second line
> Third line
Or even shorter and better, since it stops processing file after found.
awk '1; /Third/ {exit}' file
Or if its needed to take from first to third
awk '/First/ {f=1} f; /Third/ {exit}' file

Related

How to delete line with specific line numbers and save deleted and the rest?

test.txt contains:
this is a line
another line
one more line
For example, this can remove 1-2 lines, and save the rest into the rest.txt
sed -e '1,2d' test.txt > rest.txt
But the original file remains intact. Then how to get the remaining lines from the file? In this example, I want to remove the first 2 lines, save them into a file 'deleted.txt', and save the 3rd line into 'rest.txt'.
With GNU sed:
seq 1 5 | sed -e '1,2w deleted.txt' -e '1,2d' > rest.txt
w filename: Write the current pattern space to filename.
awk 'NR<=2{print $0 > "deleted.txt"}NR>2{print $0 > "rest.txt"}' test.txt
For lines(here NR) <= 2 redirect the output to deleted.
For lines(here NR) > 2 redirect the output to rest.txt.

How to save particular lines from a dat file

I have a file containing 10000 lines. I want to save data on particular lines. like line 205, 408 .. etc.
sed -n "205,408,611,814,1017,1220,1423,1626,1829,2032,2235,2438,2641,2844,3047,3250,3453,3656,3859,4062,4265,4468,4671,4874,5077,5280,5483,5686,5889,6092,6295p' evecs.dat > ext.dat
It shows an error :
sed: -e expression #1, char 8: unknown command: `,'
TO print only the 2nd and 4th line:
sed -n '2p;4p' file
Since you have many lines:
Prepare a file with all the line numbers, say here we want 2nd and 4th:
$ cat line
2
4
Prepare a string for the sed print command :
$ x=$(sed 's/$/p/' line | paste -sd";")
$ echo $x
2p;4p
Print those lines from the original file:
$ sed -n "$x" file

Using sed to keep the beginning of a line

I have a file in which some lines start by a >
For these lines, and only these ones, I want to keep the first eleven characters.
How can I do that using sed ?
Or maybe something else is better ?
Thanks !
Muriel
Let's start with this test file:
$ cat file
line one with something or other
>1234567890abc
other line in file
To keep only the first 11 characters of lines starting with > while keeping all other lines:
$ sed -r '/^>/ s/(.{11}).*/\1/' file
line one with something or other
>1234567890
other line in file
To keep only the first eleven characters of lines starting with > and deleting all other lines:
$ sed -rn '/^>/ s/(.{11}).*/\1/p' file
>1234567890
The above was tested with GNU sed. For BSD sed, replace the -r option with -E.
Explanation:
/^>/ is a condition. It means that the command which follows only applies to lines that start with >
s/(.{11}).*/\1/ is a substitution command. It replaces the whole line with just the first eleven characters.
-r turns on extended regular expression format, eliminating the need for some escape characters.
-n turns off automatic printing. With -n in effect, lines are only printed if we explicitly ask them to be printed. In the second case above, that is done by adding a p after the substitute command.
Other forms:
$ sed -r 's/(>.{10}).*/\1/' file
line one with something or other
>1234567890
other line in file
And:
$ sed -rn 's/(>.{10}).*/\1/p' file
>1234567890

Replace multiple lines with sed

I have in sample.txt the following content
abc
efg
hij
klm
nop
qrs
I have tried replacing abc with other text with
sed -i '/abc/c\This line is removed by the admin.' sample.txt
Output:
This line is removed by the admin.
efg
hij
klm
nop
qrs
It worked but for a single line.
But I am wondering how could I replace a given set of lines say 1 to 3 using sed?
If you know the line numbers, you prepend them to your pattern, like so:
sed -i '4 s/abc/c\This line is removed by the admin./' sample.txt
The above will change line 4. If you want to change ranges (say, lines 5-10), enter the start and end line numbers with a comma between:
sed -i '5,10 s/abc/c\This line is removed by the admin./' sample.txt
$ represents the last line in the file so if you wanted say, line 100 to the end:
sed -i '100,$ s/abc/c\This line is removed by the admin./' sample.txt
You may find this link helpful. Look for the section on Ranges by line number.
If your only criterion is the line numbers, then you can specify them like so:
sed -i '1,3 s/.*/This line is removed by the admin./' sample.txt
Here is an awk solution if you like to try:
awk 'NR>=1 && NR<=3 {$0="This line is removed by the admin."}1' file
This line is removed by the admin.
This line is removed by the admin.
This line is removed by the admin.
klm
nop
qrs
To write it back to the file
awk 'NR>=1 && NR<=3 {$0="This line is removed by the admin."}1' file > tmp && mv tmp file
This might work for you (GNU sed):
sed '1,3c\replace lines 1 to 3 with this single line' file
if you want to replace each line within the range use:
sed $'1,3{\\athis replaces the original line\nd}' file
or perhaps more easily:
sed '1,3s/.*/this replaces the original line/' file

sed - insert lines when text found / not found

I have issue with sed, i need to accomplish two things with a csv file
in front of each line that does not start UNES I need to add tag "BF2;"
at the start of the file (after UNES if present) I need to add a tag "UNH;"
Example (no UNES;)
50000024;IE15;041111;113901;verstuurd;Aangift;
50000024;IE15;041111;113901;verstuurd;Aangifte;
50000024;IE15;041111;113901;verstuurd;Aangifte;
Example (with UNES;)
UNES;
50000024;IE15;041111;113901;verstuurd;Aangift;
50000024;IE15;041111;113901;verstuurd;Aangifte;
50000024;IE15;041111;113901;verstuurd;Aangifte;
so far I have this:
sed -e 's/^\([^"UNES"]\)/BF2;\1/' | sed '/UNES/ a\UNH;'
THis works as long as a UNES; tag is present - I can't seem to figure out how to insert the UNH; when UNES is not present!
Any help much appreciated
Sample output:
UNES;
UNH;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
Here's how you could do it using awk:
awk 'NR==1 {if(f=/^UNES;/)print; print "UNH;"} !f{print "BF2;" $0} {f=0}' file
On the first line, if /^UNES;/ is matched, print it and set the flag f. Always print "UNH;". If the f flag has been set, don't do the next action, which works for the rest of the lines. Always reset f to 0 after the first line so all further lines have "BF2;" added to the start.
Testing it out:
$ cat file
UNES;
50000024;IE15;041111;113901;verstuurd;Aangift;
50000024;IE15;041111;113901;verstuurd;Aangifte;
50000024;IE15;041111;113901;verstuurd;Aangifte;
$ awk 'NR==1 {if(f=/^UNES;/)print; print "UNH;"} !f{print "BF2;" $0} {f=0}' file
UNES;
UNH;
BF2;50000024;IE15;041111;113901;verstuurd;Aangift;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
$ cat file2
50000024;IE15;041111;113901;verstuurd;Aangift;
50000024;IE15;041111;113901;verstuurd;Aangifte;
50000024;IE15;041111;113901;verstuurd;Aangifte;
$ awk 'NR==1 {if(f=/^UNES;/)print; print "UNH;"} !f{print "BF2;" $0} {f=0}' file2
UNH;
BF2;50000024;IE15;041111;113901;verstuurd;Aangift;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
BF2;50000024;IE15;041111;113901;verstuurd;Aangifte;
You can use this sed command:
sed '/^UNES;$/{i\
UNH;
n};s/^/BF2;/;' file.txt
details:
/^UNES;$/i\
UNH; insert a new line when UNES; is the whole line.
n replaces the pattern space with the next line
Try this, its works for me
sed '/^UNES;$/{i\
UNH;
n};s/^[0-9]*/BF2;&/;'