Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Print a list of fields passed as a variable

Tags:

bash

shell

awk

I have a file say a.txt and below are the contents of it:

bob 1 100            
lincoln 2 200  
chris 3 300        

The file contents are separated by space.

Using awk, I could access each column. Using below command to print 1st and 3rd columns separated by comma:

cat a.txt | awk ' { print $1","$3} '

and I was successful.

Now I want to pass the criteria dynamically from another shell script. By saying criteria I mean - $1","$3.

I tried the below command but it didn't work.

myvar="$1"   
awk -v a="$myvar"  ' { print a } ' a.txt

but this is printing $1 3 times as there are three rows in a.txt.

How can I pass a list of fields to awk in this way?

like image 586
Sidhu sidharth Avatar asked Sep 04 '15 11:09

Sidhu sidharth


3 Answers

The problem here is that the $ in the variable you have passed to awk is interpreted literally - it cannot be used to refer to a specific field.

For a single field, you could use something like this:

awk -v field=1 '{ print $field }' file
bob
lincoln
chris

For multiple fields, this is a little more complicated:

awk -v fields="1 3" 'BEGIN{ n = split(fields,f) }
    { for (i=1; i<=n; ++i) printf "%s%s", $f[i], (i<n?OFS:ORS) }' file
bob 100
lincoln 200
chris 300

The list of fields is passed as a string, which is split into an array. The array is then looped through, using printf to output each field, followed by either the Output Field Separator OFS or the Output Record Separator ORS, depending on whether it's the last field or not. To separate the fields with a comma, you can pass -v OFS=, as an option.

like image 52
Tom Fenech Avatar answered Nov 18 '22 03:11

Tom Fenech


Alternative to awk solution using cut which already accepts field positions via comma separated list.

cols="1,3"; cut -d" " -f"$cols" a.txt

for comma separated output pipe to tr ' ' ',' or use --output-delimiter="," cut option.

Note that this will give you the flexibility to specify input as closed or open range such as 1-3 or 2-

like image 32
karakfa Avatar answered Nov 18 '22 05:11

karakfa


You will need to pass a delimited string to awk and inside awk use split to split on that delimiter.

Something like this should work:

awk -v search='1,3' 'BEGIN{split(search, a, ",")}
               {f=""; for (i=1;i in a;i++) {printf "%s%s", f, $a[i]; f=OFS} print ""}' file

Output:

bob 100
lincoln 200
chris 300
like image 34
anubhava Avatar answered Nov 18 '22 04:11

anubhava