0

I'd like to pass a reference to any number of field variables into awk and have it print out the value for each variable for each line without using a for loop.

For example, I'd like to do something like:

var=$1":"$3":"$4
echo "aa bb cc dd" | awk -v var=$var '{print var}'

I would like an output of "aa:cc:dd." When I try it as-is, I get an output of $1":"$3":"$4. Is it possible to do this for any number of field variables in var without doing a for loop?

6 Answers 6

1

No it's not possible to do in awk with out looping but you could do it with cut:

$ var='1,3,4' 
$ echo 'aa bb cc dd' | cut -d' ' --output-delimiter ':' -f "$var"
aa:cc:dd
Sign up to request clarification or add additional context in comments.

6 Comments

well I dont know if OP really wants to know how to write this in awk. apart from that. the awk solution and cut are different. This cut solution works smoothly with op's example. however, if var=1,4,3, the output would be different.
@Kent yes cut won't reorder the fields, There isn't a nice solution to this question, I'm not sure why you would want to do it. This seemed more sane then using quoting hacks or system calls which is still using shell to do it...
If I read it again now, I notice there is single quote, not double. I thought he has 3 vars, $1-3(from script input?) and build a new var, now he want to get the corresponding field printed... anyway too complicated for the requirement. and he may not require that at all. ^_^
Oops, single quote is gone... no matter I posted anything, answer/comment, anything is wrong...first is the output suddently with :, then single quote is gone.... :~(
I don't understand most of your last two comments but it is safe to assume $1,$3 and $4 should be treated as literal strings because the expected output is aa:cc:dd so the OP really needs to use single quotes var='$1":"$3":"$4' to stop the shell expansion.
|
0
var='$1":"$3":"$4'
echo "aa bb cc dd" | awk  "{print $var}"

This will pass the variables you want as literal awk print format i.e

echo "aa bb cc dd" | awk {print $1":"$3":"$4}

8 Comments

It should be noted the shell is expanding $var before awk so awk {print $1":"$3":"$4} the lack of quoting is dangerous and could have unexpected results if the script is extended at all.
if the $xs are literal text in var, this solution would be most straightforward. I may think it too complicated...
It's no more complicated than awk, as all you are doing is passing in what you would have to do in awk anyway
I'm having trouble using this method when I try to set the field separator in the awk as tab. I can't use "\t" and '\t' is throwing an error.
Don't do this, the quoting is wrong which will lead to headaches in having to escape and or double-escape various characters (as you saw when trying to set FS) and will fail in interesting and exciting ways given various values of var.
|
0

you want to have this:

awk -v var="$var" '{n=split(var,a,":");
   for(i=1;i<=n;i++)s=s sprintf("%s",$a[i]) (i==n?"":" ");
   print s}' 

test with your example:

kent$  var="1:3:4"

kent$  echo "aa bb cc dd"|awk -v var="$var" '{n=split(var,a,":");for(i=1;i<=n;i++)s=s sprintf("%s",$a[i]) (i==n?"":" ");print s}' 
aa cc dd

3 Comments

I thought the $1,$2 would be shell variable ...that is what I came up. any better idea?
Not possible in awk without looping, I proposed using cut instead.
@sudo_O cut is one way, but may give different output in certain case. I commented your answer.
0

You can utilize system function of awk to achieve this:

var='$1":"$3":"$4'
echo "aa bb cc dd" | awk -v var="$var" '{system("set -- " $0 "; echo " var)}'

OUTPUT:

aa:cc:dd

1 Comment

Among other things, this relies on echo which is non-portable even across UNIX systems, and it will produce incorrect output if any of the text in your input string contains any of the various characters, used for escaping, globbing, wild card expansion, etc.
0

This is the most simple and robust way to do what you specifically asked for:

$ var='$1,$3,$4'

$ echo "aa\tbb\tcc\tdd" | awk -F'\t' -v OFS=":" '{print '"$var"'}'
aa:cc:dd

I still wouldn't particularly recommend doing it though as there's probably still some values of $var that would trip you up. Just pass in the field numbers you want and use a loop to print those fields

Comments

0

So if you're REALLY concerned about safety of parsing shell variables into awk, then use this template to dynamically generate hard-coded fields for printing that accepts just a bunch of numbers (plus field-number sanitization to prevent attempting to print negative field numbers) :

echo "aa bb cc dd" | 

gawk -p- -be "$( echo 1 3 4 2 0 |

    awk 'BEGIN { printf("{ print ")
               FS = "[^0-9]+"
               ORS = " } "
                RS = "^$"

     } -gsub(/[0-9]+/, "$&,", $!(NF = NF)) <= sub(/[^0-9]+$/, _)' )" OFS=':'

aa:cc:dd
    # gawk profile, created Sat May 17 08:25:47 2025

    # Rule(s)

     1  {
     1      print $1, $3, $4
    }

… or is if you wanted to print fields ...

$1, $3, $4, $2, $0

…. that are delimited by \f:\f, then

aa
  :
   cc
     :
      dd
        :
         bb
           :
            aa bb cc dd

    # gawk profile, created Sat May 17 08:25:23 2025

    # Rule(s)

     1  {
     1      print $1, $3, $4, $2, $0
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.