How to replace two lines with a blank line using SED command? - linux

I want to replace the first two lines with a blank line as below.
Input:
sample
sample
123
234
235
456
Output:
<> blank line
123
234
235
456

Delete the first line, remove all the content from the second line but don't delete it completely:
$ sed -e '1d' -e '2s/.*//' input.txt
123
234
235
456
Or insert a blank line before the first, and delete the first two lines:
$ sed -e '1i\
' -e '1,2d' input.txt
123
234
235
456
Or use tail instead of sed to print all lines starting with the third, and an echo first to get a blank line:
(echo ""; tail +3 input.txt)
Or if you're trying to modify a file in place, use ed instead:
ed -s input.txt <<EOF
1,2c
.
w
EOF
(The c command changes the given range of lines to new content)

Related

sed command to print lines between two patterns

I am trying to print lines between two patterns through sed command. But I want to include the line containing Pattern1 in the result and exclude the Pattern2.
For ex:
/PAT1/
line 1
line 2
line 3
/PAT2/
The desired output is :
/PAT1/
line 1
line 2
line 3
I have tried this :
sed -n '/PAT1/,/PAT2/{/PAT2/{d};p}' Input_File
But it is excluding both the patterns.
You can do it with awk: awk '/patt1/{flag=1}/patt2/{flag=0}flag' input_file
If input_file is:
111
222
333
444
555
awk '/222/{flag=1}/444/{flag=0}flag' input_file
gives:
222
333

Reorder Lines Based On Previous File Order Before Randomization

I have the following lines in file1:
line 1text
line 2text
line 3text
line 4text
line 5text
line 6text
line 7text
With the command cat file1 | sort -R | head -4 I get the following in file2:
line 5text
line 1text
line 7text
line 2text
I would like to order the lines (not numerically, just the same order as file1) into the following file3:
line 1text
line 2text
line 5text
line 7text
The actual data doesn't have digits. Any easy way to do this? I was thinking of doing a grep and finding the first instance in a loop. But, I'm sure you experienced guys know an easier solution. Your positive input is highly appreciated.
You can decorate with line numbers, select four random lines lines, sort by line number and remove the line numbers:
$ nl -b a file1 | shuf -n 4 | sort -n -k 1,1 | cut -f 2-
line 2text
line 5text
line 6text
line 7text
The -b a option to nl makes sure that also empty lines are numbered.
Notice that this loads all of file1 into memory, as pointed out by ghoti. To avoid that (and as a generally smarter solution), we can use a different feature of (GNU) shuf: its -i option takes a number range and treats each number as a line. To get four random line numbers from an input file file1, we can use
shuf -n 4 -i 1-$(wc -l < file1)
Now, we have to print exactly these lines. Sed can do that; we just turn the output of the previous command into a sed script and run sed with sed -n -f -. All together:
shuf -n 4 -i 1-$(wc -l < file1) | sort -n | sed 's/$/p/;$s/p/{&;q}/' |
sed -n -f - file1
sort -n sorts the line numbers numerically. This isn't strictly needed, but if we know that the highest line number comes last, we can quit sed afterwards instead of reading the rest of the file for nothing.
sed 's/$/p/;$s/p/{&;q}/ appends p to each line. For the last line, we append {p;q} to stop processing the file.
If the output from sort looks like
27
774
670
541
then the sed command turns it into
27p
774p
670p
541{p;q}
sed -n -f - file1 processes file1, using the output of above sed command as the instructions for sed. -n suppresses output for the lines we don't want.
The command can be parametrized and put into a shell function, taking the file name and the number of lines to print as arguments:
randlines () {
fname=$1
nlines=$2
shuf -n "$nlines" -i 1-$(wc -l < "$fname") | sort -n |
sed 's/$/p/;$s/p/{&;q}/' | sed -n -f - "$fname"
}
to be used like
randlines file1 4
cat can add line numbers:
$ cat -n file
1 line one
2 line two
3 line three
4 line four
5 line five
6 line six
7 line seven
8 line eight
9 line nine
So you can use that to decorate, sort, undecorate:
$ cat -n file | sort -R | head -4 | sort -n
You can also use awk to decorate with a random number and line index (if your sort lacks -R like on OS X):
$ awk '{print rand() "\t" FNR "\t" $0}' file | sort -n | head -4
0.152208 4 line four
0.173531 8 line eight
0.193475 6 line six
0.237788 1 line one
Then sort with the line numbers and remove the decoration (one or two columns depending if you use cat or awk to decorate):
$ awk '{print rand() "\t" FNR "\t" $0}' file | sort -n | head -4 | cut -f2- | sort -n | cut -f2-
line one
line four
line six
line eight
another solution could be to sort whole file
sort file1 -o file2
to pick random lines on file2
shuf -n 4 file2 -o file3

Using sed replace line in file with another file

I have a very large tab delimited file, I would like to replace a single line in this file with another. As the line has >100 columns, a simple sed 's/find/replace/' is not desirable. My newline is stored in file newline.txt
How do I achieve:
sed 's/find/newline.txt/' infile
With GNU sed:
Find line in file file.csv which contains find, append content (r) of file newline.txt and delete (d) line which contains find:
sed -e '/find/{r newline.txt' -e 'd}' file.csv
Based on GNU sed 4.2.2, also includes answers from Cyrus and Aaron
$ cat foo.txt
1 abc
2 ijk!
3 pqr
4 xyz
$ cat f1.txt
a/b/c
$ cat f2.txt
line
$ cat f3.txt
line a
line b
1) Pattern and replacement not containing characters that'll affect sed command or act weirdly due to bash substitution inside double quotes
$ sed "/3/c $(< f2.txt)" foo.txt
1 abc
2 ijk!
line
4 xyz
$ sed "s/.*3.*/$(< f2.txt)/" foo.txt
1 abc
2 ijk!
line
4 xyz
$ sed -e '/3/{r f2.txt' -e 'd}' foo.txt
1 abc
2 ijk!
line
4 xyz
2) Pattern getting affected due to bash substitution
$ sed "/!/c $(< f2.txt)" foo.txt
bash: !/c: event not found
$ sed '/!/c '"$(< f2.txt)" foo.txt
1 abc
line
3 pqr
4 xyz
$ sed "s/.*!.*/$(< f2.txt)/" foo.txt
bash: !.*/$: event not found
$ sed 's/.*!.*/'"$(< f2.txt)/" foo.txt
1 abc
line
3 pqr
4 xyz
$ sed -e '/!/{r f2.txt' -e 'd}' foo.txt
1 abc
line
3 pqr
4 xyz
3) Replacement line (single line only) containing characters affecting sed
$ sed "/3/c $(< f1.txt)" foo.txt
1 abc
2 ijk!
a/b/c
4 xyz
$ sed "s/.*3.*/$(< f1.txt)/" foo.txt
sed: -e expression #1, char 11: unknown option to `s'
$ sed "s|.*3.*|$(< f1.txt)|" foo.txt
1 abc
2 ijk!
a/b/c
4 xyz
$ sed -e '/3/{r f1.txt' -e 'd}' foo.txt
1 abc
2 ijk!
a/b/c
4 xyz
4) Replacement with multiple lines
$ sed "/3/c $(< f3.txt)" foo.txt
sed: -e expression #1, char 14: extra characters after command
$ sed "s/.*3.*/$(< f3.txt)/" foo.txt
sed: -e expression #1, char 14: unterminated `s' command
$ sed -e '/3/{r f3.txt' -e 'd}' foo.txt
1 abc
2 ijk!
line a
line b
4 xyz
From #Aaron
sed "s/^.*find.*$/$(cat newline.txt)/" infile.txt
Where find is a unique string in infile.txt that returns a single line, the line is then replaced by newline.txt
try this
sed s/find/$(< newline.txt)/ infile

Insert a space after the second character followed by every three characters

I need to insert a space after two characters, followed by a space after every three characters.
Data:
97100101101102101
Expected Output:
97 100 101 101 102 101
Attempted Code:
sed 's/.\{2\}/& /3g'
In two steps:
$ sed -r -e 's/^.{2}/& /' -e 's/[^ ]{3}/& /g' <<< 97100101101102101
97 100 101 101 102 101
That is:
's/^.{2}/& /'
catch the first two chars in the line and print them back with a space after.
's/[^ ]{3}/& /g'
catch three consecutive non-space characters and print them back followed by a space.
With GNU awk:
$ echo '97100101101102101' | awk '{print substr($0,1,2) gensub(/.{3}/," &","g",substr($0,3))}'
97 100 101 101 102 101
Note that unlike the currently accepted sed solution this will not add a blank char to the end of the line, e.g. using _ instead of a blank to make the issue visible:
$ echo '97100101101102101' | sed -r -e 's/^.{2}/&_/' -e 's/[^_]{3}/&_/g'
97_100_101_101_102_101_
$ echo '97100101101102101' | awk '{print substr($0,1,2) gensub(/.{3}/,"_&","g",substr($0,3))}'
97_100_101_101_102_101
and it would work even if the input contained blank chars:
$ echo '971 0101101102101' | sed -r -e 's/^.{2}/& /' -e 's/[^ ]{3}/& /g'
97 1 010 110 110 210 1
$ echo '971 0101101102101' | awk '{print substr($0,1,2) gensub(/.{3}/," &","g",substr($0,3))}'
97 1 0 101 101 102 101

Match specific column with grep command

I am having trouble matching specific column with grep command. I have a test file (test.txt) like this..
Bra001325 835 T 13 c$c$c$c$c$cccccCcc !!!!!68886676
Bra001325 836 C 8 ,,,,,.,, 68886676
Bra001325 841 A 6 ,$,.,,. BJJJJE
Bra001325 866 C 2 ,. HJ
And i want to extract all those lines which has a number 866 in the second column. When i use grep command i am getting all the lines that contains the number that number
grep "866" test.txt
Bra001325 835 T 13 c$c$c$c$c$cccccCcc !!!!!68886676
Bra001325 836 C 8 ,,,,,.,, 68886676
Bra001325 866 C 2 ,. HJ
How can i match specific column with grep command?
Try doing this :
$ awk '$2 == 866' test.txt
No need to add {print}, the default behaviour of awk is to print on a true condition.
with grep :
$ grep -P '^\S+\s+866\b' *
But awk can print filenames too & is quite more robust than grep here :
$ awk '$2 == 866{print FILENAME":"$0; nextfile}' *
In my case, the field separator is not space but comma. So I would have to add this, otherwise it won't work for me (On ubuntu 18.04.1).
awk -F ', ' '$2 == 866' test.txt

Resources