bash- printing two consecutive lines if a pattern found - bash

I need to search for a string in a file and print the matching lines together with their next lines in another file.
Example:
input file:
>3456/1
A
>1234/2
B
>5678/1
C
>8976/2
D
search for: /2
output:
>1234/2
B
>8976/2
D

Using grep:
$ grep -A1 '/2' file
>1234/2
B
--
>8976/2
D
From the man page:
-A num, --after-context=num
Print num lines of trailing context after each match.
You can remove the -- by piping it to grep -v '--' or if you have GNU grep then you can simply do:
$ grep --no-group-separator -A1 '/2' file
>1234/2
B
>8976/2
D
You can re-direct the output of this command to another file.

Using GNU sed
sed -n '/\/2/,+1p' file
Example:
$ sed -n '/\/2/,+1p' file
>1234/2
B
>8976/2
D

Use grep -A
See the man page:
-A num, --after-context=num
Print num lines of trailing context after each match. See also the -B and -C options.
-B num, --before-context=num
Print num lines of leading context before each match. See also the -A and -C options.
-C[num, --context=num]
Print num lines of leading and trailing context surrounding each match. The default is 2 and is equivalent to -A 2 -B 2. Note: no whitespace may be given between the option and its argument.
Here is an example:
%grep -A2 /2 input
>1234/2
B
>5678/1
--
>8976/2
D

Here is grep the correct tool, but using awk you would get:
awk '/\/2/ {print $0;getline;print $0}' file
>1234/2
B
>8976/2
D
PS you should have found this your self, using goolge. This is asked many times.

Related

deleting row from a csv file using sed and save the file without deleted row

I have a csv file from which I want to delete the second row using unix sed command.
The file.csv is represented below
a
b
c
d
so it becomes newfile.csv
a
c
d
Based on my search for solutions, the simplest way to do this seems to be using the following sed command;
sed '2d' file.csv > newfile.csv
Yet, the newfile.csv contains the deleted row
d
, not the expected
a
c
d
I am using iTerm2 on macOS Mojave
In those cases, awk is useful, too:
$ awk 'NR != 2' file.csv
a
c
d
There awk prints every row but the number 2.
If it is easier to understand:
$ cat file.csv | awk 'NR != 2'
a
c
d
Possible the formatting of your file is wrong, try this:
dos2unix file.csv
then one of these
sed '2d' file.csv
awk 'NR!=2' file.csv

Move Second Column of Each Row to a New Next Row

I can move every second row into the second column of the previous row by:
awk '{printf "%s%s",$0,(NR%2?FS:RS)}' file > newfile
But I can't do it the other way around. What I have is as below:
1 a
2 b
3 c
I need
1
a
2
b
3
c
I have checked several similar column-row shifting questions, but couldn't figure out my case. Thanks!
You can use this awk command with OFS='\n' to get output field separator as newline after forcing awk to rewrite each record with $1=$1 trick:
awk '{$1=$1} 1' OFS='\n' file
1
a
2
b
3
c
You can also use grep -o:
grep -Eo '\w+' file
1
a
2
b
3
c
Just use xargs with 1 record at a time,
xargs -n1 <file
1
a
2
b
3
c
From the man xargs page
-n max-args, --max-args=max-args
Use at most max-args arguments per command line. Fewer than max-args arguments will be used if the size (see the -s option) is exceeded, unless the
-x option is given, in which case xargs will exit.
you can use tr
cat file | tr ' ' '\n'
or sed
sed -r 's/ /\n/g' file
you get,
1
a
2
b
3
c

Deleting lines matching a string in a file

I have multiple lines in a file. some lines start in the pattern below
0 8234 <Enter_newLine>
0 12 <Enter_newLine>
1 2 <Enter_newLine>
I wanted to delete the lines which start with 0 as shown above. Can someone please help me in this
This is very simple to do in awk:
awk '!/^0/' file
Any line starting with a 0 will not be printed.
To overwrite the input file, you can use the standard trick:
awk '!/^0/' file > tmp && mv tmp file
You could also use grep:
grep -v '^0' file
The -v switch means that only lines that don't match the pattern are printed.
If you want to edit the file, you can use ed, the standard editor:
ed -s file < <(printf '%s\n' g/^0/d w q)
This uses the g/re/d construct: g to use the whole file, /re/ is the regex to work with, here ^0 to match lines starting with 0 and d to delete those lines. We then send the commands w (write) and q (quit).
The same without bashisms:
printf '%s\n' g/^0/d w q | ed -s file
You can also try sed:
sed -i '/^0[[:blank:]]\+/d' file.txt
Assuming that there can be one or more space or tab after initial 0, no other character.
This awk should do:
awk '$1!="0"' file
1 2 <Enter_newLine>
This removes line where first field is just 0.

Scripts for listing all the distinct characters in a text file

E.g.
Given a file input.txt, which has the following content:
He likes cats, really?
the output would be like:
H
e
l
i
k
s
c
a
t
,
r
l
y
?
Note the order of characters in output does not matter.
One way using grep -o . to put each character on a newline and sort -u to remove duplicates:
$ grep -o . file | sort -u
Or a solution that doesn't required sort -u or multiple commands written purely in awk:
$ awk '{for(i=1;i<=NF;i++)if(!a[$i]++)print $i}' FS="" file
How about:
echo "He likes cats, really?" | fold -w1 | sort -u
An awk way:
awk '{$1=$1}1' FS="" OFS="\n" file | sort -u
You can use sed as follows:
sed 's/./\0\n/g' input.txt | sort -u

Merge two text files at a specific location, sed or awk

I have two text files, I want to place a text in the middle of another, I did some research and found information about adding single strings:
I have a comment in the second text file called STUFFGOESHERE, so I tried:
sed '/^STUFFGOESHERE/a file1.txt' file2.txt
sed: 1: "/^STUFFGOESHERE/a long.txt": command a expects \ followed by text
So I tried something different, trying to place the contents of the text based on a given line, but no luck.
Any ideas?
This should do it:
sed '/STUFFGOESHERE/ r file1.txt' file2.txt
If you want to remove the STUFFGOESHERE line:
sed -e '/STUFFGOESHERE/ r file1.txt' -e '/STUFFGOESHERE/d' file2.txt
If you want to modify file2 in place:
sed -i -e...
(or maybe sed -i '' -e..., I'm using GNU sed 4.1.5.)
If you can use ex or ed, try
cat <<EOF | ex -e - file2.txt
/^STUFFGOESHERE/
.r file1.txt
w
q
EOF
The same script works for ed:
cat <<EOF | ed file2.txt
/^STUFFGOESHERE/
.r file1.txt
w
q
EOF
awk '/STUFFGOESHERE/{while((getline line<"file1")>0){ print line};next}1' file2
From a Unix shell (bash, csh, zsh, whatever):
: | perl -e '#c = join("", map {<>} 0..eof); print $c[0] =~ /STUFFGOESHERE/ ? $` . $c[1] . $'"'"' : $c[0]' file2.txt file1.txt > newfile2.txt

Resources