3

I am beginning to learn awk and came across something that when I run the following commands

$ echo ":a:b:c:" | awk '$1=$1' FS=":" OFS="$"
$ echo "a:b:c:" | awk '$1=$1' FS=":" OFS="$"
a$b$c$

First command returns nothing, but I expected it to return $a$b$c$, similar to the second command. And in general, it never prints anything when the field separator is at the beginning of the line. Why so?

0

3 Answers 3

8

In your awk script, printing is triggered as the default action, which in turn depends on "side-effect" evaluation of assignment $1=$1 as a pattern.

In the first case, there is an empty field before the first separator, so $1 is the empty string, which evaluates FALSE. In the second case, $1 is the non-empty string a, which evaluates TRUE, triggering the default print action.

2
  • So how does {$1=$1}1 makes it work?
    – sh.3.ll
    Jun 18, 2020 at 17:45
  • 1
    A correction: {$1=$1}1 is two pattern-action pairs: the first is {$1=$1} where the default pattern is 1, so it will evaluate on every line; the second is 1 where the default action is {print}. Jun 18, 2020 at 18:50
5

You're relying on the truth value of the first field to make awk print the record. The truth value of an empty string is false, so awk doesn't do anything other than the assignment. Print explicitly (or using some other always true condition, like 1), instead of using the first field as the check:

echo ":a:b:c:" | awk '{$1=$1; print}' FS=":" OFS="$"
2
  • So how does {$1=$1}1 makes it work?
    – sh.3.ll
    Jun 18, 2020 at 17:45
  • 1
    1 is an always-true condition, like I said in my answer.
    – muru
    Jun 18, 2020 at 17:46
4
  1. Don't let the result of an action evaluate to be a condition unless you have a very specific need (e.g. you try to remove a char if present and want to do something if that succeeds).
  2. Code is more readable when you see variables being set before you see the code that uses them so don't list variable assignments in the file list after the script unless you have a very specific need (e.g. changing values between files), list them up front using -v or BEGIN or an assignment before the call to awk that you can access from ENVIRON[] (see https://stackoverflow.com/q/19075671/1745001).
  3. Use single quotes around all strings (including scripts) in shell unless you have a very specific need to use double quotes or no quotes (see https://mywiki.wooledge.org/Quotes).

So your script should be awk -F':' -v OFS='$' '{$1=$1}1'.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .