get entries within a paragraph using sed or awk - awk

I've a file as follows:
[para1]
abc-1-10 interpreter=/bin/sed
abc-1-11 interpreter=/bin/sed
[para2]
abc-2-100 interpreter=/bin/sed
abc-2-205 interpreter=/bin/sed
abc-2-206 interpreter=/bin/sed
[para3]
abc-3-15 interpreter=/bin/sed
abc-3-18 interpreter=/bin/sed
I need each para written to a separate file i.e. the line [para1] and the two entries i.e. abc-1-10 and abc-1-11
I tried
awk -v Var="\[para" '$1~Var{p=1}/^$/{p=0}p /tmp/filename
which gives an error as: awk:warning: escape sequence '\[' treated as plain '['
I also tried awk -v Var="para" '$1~Var{p=1}/^$/{p=0}p /tmp/filename and it prints the whole file!!. Any help is much appreciated.

Using awk
$ awk '/^\[para/ {close(para);para="file"++c".txt"}{print > para}' input_file
$ head file*.txt
==> file1.txt <==
[para1]
abc-1-10 interpreter=/bin/sed
abc-1-11 interpreter=/bin/sed
==> file2.txt <==
[para2]
abc-2-100 interpreter=/bin/sed
abc-2-205 interpreter=/bin/sed
abc-2-206 interpreter=/bin/sed
==> file3.txt <==
[para3]
abc-3-15 interpreter=/bin/sed
abc-3-18 interpreter=/bin/sed

This might work for you (GNU csplit):
csplit -q -f file -b %d.txt inputFile '/^\[/' '{*}' && rm file0.txt
Quiet, prefix of file, suffix of n.txt and remove the first empty file.

Related

Remove '||'(double pipe) separated multiple columns from file using shell script command

Please suggest perfect shell script command to remove last two '||' delimiter separated columns from the file.(Lets assume below example)
File Name: abc.dat
"a1"||"a2"||"a3"||"a4"
"b1"||"b2"||"b3"||"b4"
"c1"||"c2"||"c3"||"c4"
output should be like :
"a1"||"a2"
"b1"||"b2"
"c1"||"c2"
I tried below cut and awk command but not worked:
awk -F '||' '{print $1$2}' ${file} >> ${file}
cut -d'||' -f2 --complement ${file} >> ${file} (not working as cut: the delimiter must be a single character)
With your shown samples, please try following. Make field separator as ||(escaping it to treat literal character) along with setting OFS to || too. Then print 1st and 2nd fields for each line of Input_file.
awk -F'\\|\\|' -v OFS="||" '{print $1,$2}' Input_file
Once you are happy with results of above command, also to make changes into Input_file itself try following.
awk -F'\\|\\|' -v OFS="||" '{print $1,$2}' Input_file > temp && mv temp Input_file
2nd solution: Using GNU grep try following.
grep -oP '^.*?\|\|"[^"]*' Input_file
Rather than assuming || is the delimiter, assume that | is the delimiter and the second field is empty.
$ cut -d'|' -f1-3 <<EOF
> "a1"||"a2"||"a3"||"a4"
> "b1"||"b2"||"b3"||"b4"
> "c1"||"c2"||"c3"||"c4"
> EOF
"a1"||"a2"
"b1"||"b2"
"c1"||"c2"
(This assumes that || was chosen for some aesthetic reason, rather than to allow for single pipes in each field.)
You may use:
awk '{sub(/(\|{2}[^|]*){2}$/, "")} 1' file
"a1"||"a2"
"b1"||"b2"
"c1"||"c2"
Or if you just want to remove last 2 columns without caring how many columns are there in total use:
awk -F '\\|{2}' -v OFS='||' '{
$NF = $(NF-1) = ""
sub(/([|]{2})*$/, "")
} 1' file

Print if the field starts with a specific string using awk

I have a list like this in chrs.txt file:
chr22
chr21
chrUn_gl000225
chrUn_gl000222
chrM
the result I want:
chr22
chr21
I want to print lines if they do not include chrM and chrUn. So I want to filter string chrM and strings including chrUn. To do so I tried codes below but I could only filter chrM.
awk '($1 != "chrM" && $1 != "chrUn")' chrs.txt
awk '($1 != "chrM" && $1 != "/^chrUn/")' chrs.txt
awk '($1 != "chrM" && $1 != "chrUn_*")' chrs.txt
If you could help I will appreciate it.
all you need is:
awk '!/^chr(Un|M)/' file
Also grep can do that.
grep -Ev '^chr(Un|M)' file
GNU ed(1)
printf '%s\n' 'v/^chr\(Un\|M\)/p' | ed -s file
In bash, you can do the comparison like this (assuming line contains a single line of the file, i.e. I've excluded the loop over the file's lines here):
if [[ $line != chrUn* ]] && [[ $line != chrM* ]]; then
echo $line
fi;
awk:
awk '$0!~/^chr(Un|M)/'
sed:
sed -rne '/^chr(Un|M)/!p'
grep:
grep -Ev "^chr(Un|M)"
bash:
for LINE in $(<your_file.txt); do [[ $LINE =~ ^chr(Un|M) ]] || echo $LINE ; done
You should use one of the first three option since they are more portable across differente shell.

Printing only part of next line after matching a pattern

I want to print next sentence after match
My file content like this:
SSID:CoreFragment
Passphrase:WiFi1234
SSID:CoreFragment_5G
Passphrase:WiFi1234
SSID:Aleph_inCar
Passphrase:1234567890
As per my search,e.g. If I found WIFI-3(SSID) than, I want to print 1234ABCD. I used this command to search SSID:
grep -oP '^SSID:\K.+' file_name
After this search I want to print Passphrase of that particular match.
I'm working on Ubuntu 18.04
ssid=$(grep -oP &apos;^SSID:\K.+&apos; list_wifi.txt)
for ssid in $(sudo iwlist wlp2s0 scan | grep ESSID | cut -d &apos;"&apos; -f2)
do
if [ $ssid == $ssid_name ]; then
echo "SSID found...";
fi
done
I want to print next line after match.
another awk
$ awk -F: -v s="$ssid" '$0=="SSID:"s{c=NR+1} c==NR{print $2; exit}' file
1234ABCD
will only print the value if it's on the next line.
awk -F: '/WIFI-3/{getline;print $2; exit}' file
1234ABCD
Robustly (wont fail due to partial matches, etc.) and idiomatically:
$ awk -F':' 'f{print $2; exit} ($1=="SSID") && ($2=="WIFI-3"){f=1}' file
1234ABCD
Please try the following:
ssid="WIFI-3"
passphrase=$(grep -A 1 "^SSID:$ssid" file_name | tail -n 1 | cut -d: -f2)
echo "$passphrase"
which yields:
1234ABCD
Since code tags have changed the look of samples so adding this now.
var=$(awk '/SSID:[a-zA-Z]+-[0-9]+/{flag=1;next} flag{sub(/.*:/,"");value=$0;flag=""} END{print value}' Input_file)
echo "$var"
Could you please try following.
awk '/Passphrase/ && match($0,/WIFI-3 Passphrase:[0-9a-zA-Z]+/){val=substr($0,RSTART,RLENGTH);sub(/.*:/,"",val);print val;val=""}' Input_file
Using Perl
$ export ssid="WIFI-3"
$ perl -0777 -lne ' /SSID:$ENV{ssid}\s*Passphrase:(\S+)/ and print $1 ' yash.txt
1234ABCD
$ export ssid="Aleph_inCar"
$ perl -0777 -lne ' /SSID:$ENV{ssid}\s*Passphrase:(\S+)/ and print $1 ' yash.txt
1234567890
$
$ cat yash.txt
SSID:CoreFragment
Passphrase:WiFi1234
SSID:CoreFragment_5G
Passphrase:WiFi1234
SSID:Aleph_inCar
Passphrase:1234567890
SSID:WIFI-1
Passphrase:1234ABCD
SSID:WIFI-2
Passphrase:123456789
SSID:WIFI-3
Passphrase:1234ABCD
You can capture it in variables as
$ passphrase=$(perl -0777 -lne ' /SSID:$ENV{ssid}\s*Passphrase:(\S+)/ and print $1 ' yash.txt)
$ echo $passphrase
1234567890
$

Why does awk not filter the first column in the first line of my files?

I've got a file with following records:
depots/import/HDN1YYAA_15102018.txt;1;CAB001
depots/import/HDN1YYAA_20102018.txt;2;CLI001
depots/import/HDN1YYAA_20102018.txt;32;CLI001
depots/import/HDN1YYAA_25102018.txt;1;CAB001
depots/import/HDN1YYAA_50102018.txt;1;CAB001
depots/import/HDN1YYAA_65102018.txt;1;CAB001
depots/import/HDN1YYAA_80102018.txt;2;CLI001
depots/import/HDN1YYAA_93102018.txt;2;CLI001
When I execute following oneliner awk:
cat lignes_en_erreur.txt | awk 'FS=";"{ if(NR==1){print $1}}END {}'
the output is not the expected:
depots/import/HDN1YYAA_15102018.txt;1;CAB001
While I am suppose get only the frist column:
If I run it through all the records:
cat lignes_en_erreur.txt | awk 'FS=";"{ if(NR>0){print $1}}END {}'
then it will start filtering only after the second line and I get the following output:
depots/import/HDN1YYAA_15102018.txt;1;CAB001
depots/import/HDN1YYAA_20102018.txt
depots/import/HDN1YYAA_20102018.txt
depots/import/HDN1YYAA_25102018.txt
depots/import/HDN1YYAA_50102018.txt
depots/import/HDN1YYAA_65102018.txt
depots/import/HDN1YYAA_80102018.txt
depots/import/HDN1YYAA_93102018.txt
Does anybody knows why awk is skiping the first line only.
I tried deleting first record but the behaviour is the same, it will skip the first line.
First, it should be
awk 'BEGIN{FS=";"}{ if(NR==1){print $1}}END {}' filename
You can omit the END block if it is empty:
awk 'BEGIN{FS=";"}{ if(NR==1){print $1}}' filename
You can use the -F command line argument to set the field delimiter:
awk -F';' '{if(NR==1){print $1}}' filename
Furthermore, awk programs consist of a sequence of CONDITION [{ACTIONS}] elements, you can omit the if:
awk -F';' 'NR==1 {print $1}' filename
You need to specify delimiter in either BEGIN block or as a command-line option:
awk 'BEGIN{FS=";"}{ if(NR==1){print $1}}'
awk -F ';' '{ if(NR==1){print $1}}'
cut might be better suited here, for all lines
$ cut -d';' -f1 file
to skip the first line
$ sed 1d file | cut -d';' -f1
to get the first line only
$ sed 1q file | cut -d';' -f1
however at this point it's better to switch to awk
if you have a large file and only interested in the first line, it's better to exit early
$ awk -F';' '{print $1; exit}' file

reading a variable in awk from the command line after entering the command

I try searching a file by using awk. How can I ask awk to read a variable from the command line as a name to get searched in the file:
this is a regular way I use to search the file and I can ask the user to enter a name to search in the file.txt
awk -f myAwk.awk file.txt
How can I manage it like this :
awk -f myAwk.awk file.txt nameToSearch
How can I use ARGC and ARGV to search the nameToSearch in the file.txt?
What you're probably looking for is
awk [-W option] [-F value] [-v var=value] [--] 'program text' [file ...]
so
awk -v MYVAR=nameToSearch -v OTHERVAR=somethingElse -f myAwk.awk file.txt
Is that it? of course order of switches ( -f, -v ) does not matter. Obvously you then need to include MYVAR ( OTHERVAR ) for a variable identifier inside awk program itself.
To pass a variable to awk, you can use the -v command.
For example:
cat file.txt | awk -v p="stringToSearch" '$0 ~ p'
In this command, tou replace stringToSearch with a pattern (please keep the double quote, they are useful for preserving spaces). The awk command $0 ~ p compares the current line to the given pattern.
Another approach is to build the awk command from the shell:
p="stringToSearch"
awk "/$p/" file.txt
You must use double quotes in the command to force expanding $p.
If it's permitted to change the order of arguments, so that we can do this:
awk -f myAwk.awk nameToSearch file.txt
then you can do:
awk 'NR==1 { nameToSearch = $0; next} { ... rest of myAwk.awk here ...}' nameToSearch file.txt
You can of course add the NR==1 {...} block to the beginning of your myAwk.awk file, then continue using:
awk -f myAwk.awk nameToSearch file.txt
The technique Piotr Wadas describes has the same effect:
awk -v nameToSearch=whatever -f myAwk.awk file.txt
and that's what I'd use myself, rather than passing whatever as an additional argument to the script. Passing whatever as an additional argument is what scripters had to do before the -v facilities were added to awk. If writing -v nameToSearch= is too verbose, then I'd wrap the whole thing up in a shell script, and say:
myShellScript whatever file.txt
But you asked how to do it by passing whatever as an additional argument to the awk script, so that's what I demonstrated.