writing an awk command to print every line that has at least one field - linux

How can I write an awk command that prints only lines with at least one field
awk '{if (NF>0) print }'

You command works, and prints lines with one or more fields. But awk prints by default, so you can simplify it:
awk 'NF > 0' file.txt

Related

bash: awk print with in print

I need to grep some pattern and further i need to print some output within that. Currently I am using the below command which is working fine. But I like to eliminate using multiple pipe and want to use single awk command to achieve the same output. Is there a way to do it using awk?
root#Server1 # cat file
Jenny:Mon,Tue,Wed:Morning
David:Thu,Fri,Sat:Evening
root#Server1 # awk '/Jenny/ {print $0}' file | awk -F ":" '{ print $2 }' | awk -F "," '{ print $1 }'
Mon
I want to get this output using single awk command. Any help?
You can try something like:
awk -F: '/Jenny/ {split($2,a,","); print a[1]}' file
Try this
awk -F'[:,]+' '/Jenny/{print $2}' file.txt
It is using muliple -F value inside the [ ]
The + means one or more since it is treated as a regex.
For this particular job, I find grep to be slightly more robust.
Unless your company has a policy not to hire people named Eve.
(Try it out if you don't understand.)
grep -oP '^[^:]*Jenny[^:]*:\K[^,:]+' file
Or to do a whole-word match:
grep -oP '^[^:]*\bJenny\b[^:]*:\K[^,:]+' file
Or when you are confident that "Jenny" is the full name:
grep -oP '^Jenny:\K[^,:]+' file
Output:
Mon
Explanation:
The stuff up until \K speaks for itself: it selects the line(s) with the desired name.
[^,:]+ captures the day of week (in this case Mon).
\K cuts off everything preceding Mon.
-o cuts off anything following Mon.

Awk 3rd column if second coulmn matches with a variable

I am new to Awk and linux. I want to print 3rd column if 2nd column matches with a variable.
file.txt
1;XYZ;123
2;ABC;987
3;ZZZ;999
So I want to print 987, After checking if 2nd column is ABC
name="ABC"
awk -F';' '$2==$name { print $3 }' file.txt
But this is not working. Please help. Please note, I want to use AWK only, to understand how this can be achieved using awk.
Do following and it should fly then. In awk variables don't work like shell you have to explicitly mention them by using -v var_name in awk code.
name="ABC"
awk -F';' -v name="$name" '$2==name{ print $3 }' file.txt

How To Substitute Piped Output of Awk Command With Variable

I'm trying to take a column and pipe it through an echo command. If possible, I would like to keep it in one line or do this as efficiently as possible. While researching, I found that I have to use single quotes to expand the variable and to escape the double quotes.
Here's what I was trying:
awk -F ',' '{print $2}' file1.txt | while read line; do echo "<href=\"'${i}'\">'${i}'</a>"; done
But, I keep getting the number of lines than the single line's output. If you know how to caputure each line in field 4, that would be so helpful.
File1.txt:
Hello,http://example1.com
Hello,http://example2.com
Hello,http://example3.com
Desired output:
<href="http://example1.com">http://example1.com</a>
<href="http://example2.com">http://example2.com</a>
<href="http://example3.com">http://example3.com</a>
$ awk -F, '{printf "<href=\"%s\">%s</a>\n", $2, $2}' file
<href="http://example1.com">http://example1.com</a>
<href="http://example2.com">http://example2.com</a>
<href="http://example3.com">http://example3.com</a>
Or slightly briefer but less robustly:
$ sed 's/.*,\(.*\)/<href="\1">\1<\/a>/' file
<href="http://example1.com">http://example1.com</a>
<href="http://example2.com">http://example2.com</a>
<href="http://example3.com">http://example3.com</a>

How does the shell generate input for awk

Say I have a file1 containing:
1,2,3,4
I can use awk to process that file like this;
awk -v FS="," '{print $1}' file1
Also I can invoke awk with a Here String, meaning I read from stdin:
awk -v FS="," '{print $1}' <<<"9,10,11,12"
Command 1 yields the result 1 and command 2 yields 9 as expected.
Now say I have a second file2:
4,5
If I parse both files with awk sequentally:
awk -v FS="," '{print $1}' file1 file2
I get:
1
4
as expected.
But if I'm mixing reading from stdin and reading from files, the content I'm reading from stdin gets ignored and only the content in the files get processed sequentially:
awk -v FS="," '{print $1}' file1 file2 <<<"9,10,11,12"
awk -v FS="," '{print $1}' file1 <<<"9,10,11,12" file2
awk -v FS="," '{print $1}' <<<"9,10,11,12" file1 file2
All three commands yield:
1
4
which means the content from stdin simply gets thrown away. Now what is the shell doing?
Interestingly if I change command 3 to:
awk -v FS="," '{print $1}' <<<"9,10,11,12",file1,file2
I simply get 9 , which makes sense, as file1/2 are just two more fields from stdin. But why is then
awk -v FS="," '{print $1}' <<<"9,10,11,12" file1 file2
not expanded to
awk -v FS="," '{print $1}' <<<"9,10,11,12 file1 file2"
which would also yield the result 9?
And why does the content from stdin gets ignored? The same question arises for command 1 and 2. What is the shell doing here?
I tried out the commands on: GNU bash, version 4.2.53(1)-release
Standard input and input from files don't mix together well. This behavior is not exclusive to awk, you will find it in a lot of command line applications. It is logical if you think of it like this:
Files need to be processed one by one. The consuming application does not have control over when the input behind STDIN starts and stops. Look at echo a,b,c | awk -F, '{print $1}' file1 file2. In what order do the incoming "files" need to be read? When If you think about when FNR would need to be reset, or what FILENAME should be, it becomes clear that it is hard to make this right.
One trick that you can play, is to let awk (or any other program) read from a file descriptor generated by the shell. awk -F, '{print $1}' file1 <(echo 4,5,6) file2 will do what you expected in the first place.
What happens here, is that a proper file descriptor is created with the <(...) syntax (say: /proc/self/fd/11), and the reading program can treat it just like a file. It is the second argument, so it is the second file. FNR and FILENAME are all clear what they should be.

Linux Awk help on code

I need to print the contents of a file, and give a title to each column, leaving enough space to be readable, and then I need to output this into a new file. I followed this tutorial for a good while but I've gotten stuck.
http://www.thegeekstuff.com/2010/01/awk-introduction-tutorial-7-awk-print-examples
This is the example code they use, which would give me exactly what I need to do with mine. But it will not work when I adjust it.
$ awk 'BEGIN {print "Name\tDesignation\tDepartment\tSalary";}
{print $2,"\t",$3,"\t",$4,"\t",$NF;}
END{print "Report Generated\n--------------";
}' employee.txt
This is mine, as unlike the example, I want the whole document printed and don't really want this "report generated" nonsense under it. I tried adding {print;}' to the end after end, and made sure to start a new line and... nothing.
$ awk 'BEGIN {Print "Firstname\tLastname\tPoints";} END > awktest.txt > done
Where have I gone wrong? It keeps giving me the response Source line 2.
To remove the footline, just drop out anything starting from END till the closing ':
awk 'BEGIN {print "Name\tDesignation\tDepartment\tSalary";} {print $2,"\t",$3,"\t",$4,"\t",$NF;}' employee.txt
In your second example, you left out the closing ', and I suspect you put one more ">" than needed:
awk 'BEGIN {print "Firstname\tLastname\tPoints";}' awktest.txt > done
The latter example will however silently ignore everything read from "awktest.txt".
It looks like what you need is just to insert a header line, which can easily be done with sed (as well as awk) or with cat
$ sed '1iFirstname\tLastname\tPoints' file > output.file
or
$ awk 'BEGIN{print "Firstname\tLastname\tPoints"} 1' file > output.file
or
$ cat <(echo -e "Firstname\tLastname\tPoints") file > output.file
It seems you have missed out the actual printing of the columns and a source file, also I read that you don't need any END actions...
awk 'BEGIN {Print "Firstname\tLastname\tPoints";} END > awktest.txt > done`
Should be...
awk 'BEGIN {Print "Firstname\tLastname\tPoints";}{print $1,"\t",$2,"\t",$3;}' source_file.txt > awktest.txt`
Just remember to change the $1,$2,$3 to what columns on the source file you need.
FYI. I'm no expert, just reading the tuts :)
The awk print function is named print, not Print. idk why all the solutions are including ,"\t", in their print statements. You don't want that - you want to set -v OFS='\t' at the start of the script and then just use , between fields. All you want is:
awk -v OFS='\t' '
BEGIN {print "Name", "Designation", "Department", "Salary"}
{print $2, $3, $4, $NF}
}' employee.txt
assuming those are the correct field numbers you want to print from your data. Sample input/output in your question would be extremely useful to help us answer it.

Resources