Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I know this command

awk '{for(x=1;$x;++x)print $x}' 

will print out all columns in a line.

wouldn't this ++x change x to 2, and thus print $2 first? As I understood based on this: http://stackoverflow.com/questions/1812990/incrementing-in-c-when-to-use-x-or-x

And what does the $x do in for(x=1;$x;++x) ?

share|improve this question

3 Answers 3

up vote 13 down vote accepted

No. The for(i=0;i<10;i++) is a classic programming construct (see Traditional for loops) that is present in many languages. It can be broken down to:

start-expression; end-condition; end-of-iteration-expression

In other words, what I wrote above means "initialize i to 0 and, while i is less than 10, do something and then increment i by 1. Yes the syntax is confusing but that's just the way it is. The end-of-iteration-expression (++x in this case) is executed once at the end of each loop. It is equivalent to writing:

while(i<10){print i; ++i}

As for the $x, I believe that just checks that a field of that number exists and that its contents do not evaluate to false (as explained in Mathias's answer below). $N will return true if the field number N exists and is not a type of false. For example:

$ echo "a b c d" | awk '($4){print "yes"}'
yes
$ echo "a b c d" | awk '($14){print "yes"}' ## prints nothing, no $14
$ echo "a b c 0" | awk '($4){print "yes"}' ## prints nothing, $4 is 0

As you can see above, the first command prints yes because there is a $4. Since there is no $14, the second prints nothing. So, to get back to your original example:

awk '{for(x=1;$x;x++)print $x}' 
          ___ __ ___
           |   |  |
           |   |  |-----> increment x by 1 at the end of each loop.
           |   |--------> run the loop as long as there is a field number x
           |------------> initialize x to 1
share|improve this answer
    
cool stuff, good explanation :) –  Ramesh Aug 8 at 14:22
    
But why if I write ` echo 'a b c d e' | awk '{for(x=1;$5;++x)print NR,$x}'` I have an infinite loop? With echo 'a b c d ' | awk '{for(x=1;$5;++x)print NR,$x}' it prints nothing as expected. –  Hastur Aug 8 at 14:25
    
@Hastur because there will always be a $5. So, every time the loop runs, it checks whether $5 exists. Because it does, the loop will be executed. This will go on until there is no $5 which will never happen because your input has at least 5 fields. The second prints nothing because the condition fails immediately: there is no $5. –  terdon Aug 8 at 14:31
    
The first part is not a condition. It's more like start-expression; end-condition; end-of-iteration-expression (note that the end-of-iteration-expression doesn't have to be an increment). –  Stéphane Chazelas Aug 8 at 14:40
1  
You should add i=0; before while(i<10){print i; ++i}, otherwise it's not equivalent and just UB. –  gurka Aug 8 at 19:04

Since terdon provided a comprehensive answer I just want to add that if any column evaluates to false, the for statement ends the loop, as you can see in this example:

$ echo 1 2 3 4 5 0 6|awk '{for(x=1;$x;++x)print $x}' 
1
2
3
4
5
share|improve this answer
2  
A more correct awk program would be {for(x=1;$x"";++x)print $x}. This works because it fixes the type of the test expression as a string, rather than a numeric string, and a string is false only if it is empty. With the default FS, an empty field is possible only at the end of the fields. –  rici Aug 8 at 19:26
    
@rici, it means your program wouldn't stop when it meets 0 in a line, right? –  Zen Aug 9 at 2:56
    
@rici, I've tested it, it avoid the 0 problem. It's quite important in this issue, I think you really should write a supplement answer for this point. Great point. –  Zen Aug 9 at 3:00
  1. ++x and x++ are functionally equivalent when used stand-alone.  As discussed in the Stack Overflow question that you referenced,

    • There may be performance (i.e., timing) differences.
    • The results of something = ++x; and something = x++; are different – but your example isn’t doing that.

    So, as far as the incrementing of x is concerned, your example is equivalent to

    awk '{for(x=1;$x;x++) print $x}'
    
  2. The standalone $x is equivalent to $x != "", so the loop will iterate until it encounters a blank field.  This is a lazy shortcut for x <= NF, where NF is the number of fields in the current record (line).  For the purposes of your example, this is harmless, AFAICT.  But, if you specify a non-default field separator,

    awk -F, '{for(x=1;$x;++x) print $x}'
    

    this will try to do the same as your example, but splitting lines at commas.  If you type a b, it will output a b.  If you type a,b, it will print a and b on separate lines.  But if you input a,,b, it will output a and then stop, because $2 is null.

share|improve this answer
3  
$x is not equivalent to $x != "" because values like 0, +0, " 0", -0e12 also all evaluate to false. –  Stéphane Chazelas Aug 8 at 14:46
1  
@StéphaneChazelas: It's more complicated than that. "0" only evaluates to false if it's considered a numeric string. awk 'BEGIN {a="0";if(a)print a" is true";else print a" is false"'}. Contrast the numeric string case: awk -v a=0 'BEGIN {if(a)print a" is true";else print a" is false"'} or awk 'BEGIN {a=ARGV[1];if(a)print a" is true";else print a" is false"'} 0 –  rici Aug 9 at 5:32
    
@StéphaneChazelas (of course, in the context of G-Man's incorrect assertion, your statement is correct because a field is a numeric string context.) –  rici Aug 9 at 7:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.