Can't do operation with awk command [duplicate] - shell

This question already has answers here:
Print second-to-last column/field in `awk`
(10 answers)
Closed 7 years ago.
What we have to do if input is variable each time and on the bases of that input we have to again make another operation on that output of first command. please refer below example.
suppose I executed x command on terminal and it gives me output as below (space separated):
abc efg hij klm nop qrs uvw
abc efg hij klm qrs uvw
Sometimes there are 6 columns and sometimes there are 5 columns.
I pipe this output to awk command to print the 6th column i.e. qrs, it returns the correct result in the 1st case but in second case it shows uvw.

If you want the last but one column then you can use of NF variable:
awk '{print $(NF-1)}' file

See this awk and the output!
awk '{print NF, $NF, $6}' <<EOF
abc efg hij klm nop qrs uvw
abc efg hij klm qrs uvw
EOF
awk starts counting from 1, so everything is correct.

Related

How to find and merge some specific lines from one file B to another file A in linux with condition that lines in file B can be increase or decrease

File A:
abc
bcd
def
ghi
jkl
File B:
bcd
def
klm
Desired output:
abc
bcd
def
klm
ghi
jkl
Give this awk one-liner a try:
awk '!a[$0]++' fileA fileB > output
It works for your example files.
cat A B | sort -u will remove the repeated ones and do sorts, #Kent 's anwser is more elegant, but still, the output doesn't satisfy your description.

BASH - Split file into several files based on conditions

I have a file (input.txt) with the following structure:
>day_1
ABC
DEF
GHI
>day_2
JKL
MNO
PQR
>day_3
STU
VWX
YZA
>month_1
BCD
EFG
HIJ
>month_2
KLM
NOP
QRS
...
I would like to split this file into multiple files (day.txt; month.txt; ...). Each new text file would contain all "header" lines (the one starting with >) and their content (lines between two header lines).
day.txt would therefore be:
>day_1
ABC
DEF
GHI
>day_2
JKL
MNO
PQR
>day_3
STU
VWX
YZA
and month.txt:
>month_1
BCD
EFG
HIJ
>month_2
KLM
NOP
QRS
I cannot use split -l in this case because the amount of lines is not the same for each category (day, month, etc.). However, each sub-category has the same number of lines (=3).
EDIT: As per OP adding 1 more solution now.
awk -F'[>_]' '/^>/{file=$2".txt"} {print > file}' Input_file
Explanation:
awk -F'[>_]' ' ##Creating field separator as > or _ in current lines.
/^>/{ file=$2".txt" } ##Searching a line which starts with > if yes then creating a variable named file whose value is 2nd field".txt"
{ print > file } ##Printing current line to variable file(which will create file name of variable file's value).
' Input_file ##Mentioning Input_file name here.
Following awk may help you on same.
awk '/^>day/{file="day.txt"} /^>month/{file="month.txt"} {print > file}' Input_file
You can set the record separator to > and then just set the file name based on the category given by $1.
$ awk -v RS=">" 'NF {f=$1; sub(/_.*$/, ".txt", f); printf ">%s", $0 > f}' input.txt
$ cat day.txt
>day_1
ABC
DEF
GHI
>day_2
JKL
MNO
PQR
>day_3
STU
VWX
YZA
$ cat month.txt
>month_1
BCD
EFG
HIJ
>month_2
KLM
NOP
QRS
Here's a generic solution for >name_number format
$ awk 'match($0, /^>[^_]+_/){k = substr($0, RSTART+1, RLENGTH-2);
if(!(k in a)){close(op); a[k]; op=k".txt"}}
{print > op}' ip.txt
match($0, /^>[^_]+_/) if line matches >name_ at start of line
k = substr($0, RSTART+1, RLENGTH-2) save the name portion
if(!(k in a)) if the key is not found in array
a[k] add key to array
op=k".txt" output file name
close(op) in case there are too many files to write
print > op print input record to filename saved in op
Since each subcategory is composed of the same amount of lines, you can use grep's -A / --after flag to specify that number of lines to match after a header.
So if you know in advance the list of categories, you just have to grep the headers of their subcategories to redirect them with their content to the correct file :
lines_by_subcategory=3 # number of lines *after* a subcategory's header
for category in "month" "day"; do
grep ">$category" -A $lines_by_subcategory input.txt >> "$category.txt"
done
You can try it here.
Note that this isn't the most efficient solution as it must browse the input once for each category. Other solutions could instead browse the content and redirect each subcategory to their respective file in a single pass.

Using awk, eliminate any empty fields in a file and print in proper format

how to use awk on the following file named "awk.txt" and print all fields in proper length of space or tab length between.
# cat /root/awk.txt
abc hij klm
def pqr hij
mmm fgf hgt
yyt ghf jkw
I wanted to use awk on this and print in the following proper format.
abc hij klm
def pqr hij
mmm fgf hgt
yyt ghf jkw
Please help!!
Use the column command from coreutils:
column -t file
In this special case, where all entries have the same length, the following awk command would do the trick as well, however column can do the job even if the entries have different length:
awk '{$1=$1}1' OFS=' ' file
This line of awk will format the output using printf (documentation)
awk '{printf "%3s\t%3s\t%3s\n",$1,$2,$3}' awk.txt
If you want to strip the first line starting with #
awk '!/^#/{printf "%3s\t%3s\t%3s\n",$1,$2,$3}'

how to get the lines from one pattern to other pattern when those pattern are repeated by sed command

if i have file like this
test.txt
abc naveen
abc cde
naveen cde
kumar
naveen
abc
cde
abc
naveen
cde
Question 1: In this we have repeated patterns like abc, navee, cdf etc
Now we have to get the lines from first occurrence of one pattern to any second occurrence of another pattern
For example, I want to get the lines from the 2nd occurrence of abc to the 3rd occurrence of naveen i.e we get output as
abc cde
naveen cde
kumar
naveen
Question 2 (this question is continue to above question):
I want to get only the lines between them (exclude those abc and naveen )
So, I want output as
cde
naveen cde
kumar
this can be done by using sed command ....
so any one please give me the answer for this
try this
a=2
b=3
abcocc=`awk '$0~/abc/{print NR}' txt | awk -v occ=$a 'NR==occ{print $0}' `
naveenocc=`awk '$0~/naveen/{print NR}' txt | awk -v occ=$b 'NR==occ{print $0}'`
1) awk -v abc=$abcocc -v naveen=$naveenocc 'NR>=abc&&NR<=naveen{print $0}' txt
2) awk -v abc=$abcocc -v naveen=$naveenocc 'NR>abc&&NR<naveen{print $0}' txt
a is occurrence of abc and b is occurrence of Naveen and txt is input file. try and let me know if modification is needed.

How to append some command output at the end of each line in a Vi file?

Suppose I have a vi file as the following:
cat file1
abc 123 pqr
lmn 234 rst
jkl 100 mon
I want to take the 2nd field of each line (viz, in this case is 123, 234 and 100) and append it to the end of that same line.
How will I do that?
The output should look like the following:
abc 123 pqr 123
lmn 234 rst 234
jkl 100 mon 100
With awk:
$ awk '{NF=NF+1; $NF=$2}1' file
abc 123 pqr 123
lmn 234 rst 234
jkl 100 mon 100
It increments the number of field in one and sets the last one as the 2nd. Then 1 is a true condition, which is evaluated as the default awk behaviour: {print $0}.
Or also
awk '{print $0, $2}' file
It prints the full line plus the second field.
Or even shorter, thanks Håkon Hægland!:
awk '{$(NF+1)=$2}1' file
You have many ways to do that in Vi(m). This is the simplest that comes to my mind:
:%norm 0f<space>yaw$p
Explanation:
:{range}norm command executes normal mode command on each line in {range}
% is a shortcut range meaning "all lines in the buffer" so we will execute what follows on every line in the buffer
0 puts the cursor on the first column on the current line (not strictly necessary but good practice)
f<space> jumps the cursor on the first <space> after the cursor on the current line
yaw yanks the word and the <space> under the cursor
$ jumps to the end of the line
p pastes the previously yanked text
prompt with mark, you can do it in vi
:%s/\( [^ ]*\)\(.*\)/\1\2\1/
Another way, Using sed
sed -r 's/( [^ ]*)(.*)/\1\2\1/' file

Resources