Reputation: 11377
Why is the leading space not printed in the following example?
$ echo " foo bar" | awk '{ $2 = "baz"; print $0 }'
foo baz
Upvotes: 2
Views: 86
Reputation: 203169
Whenever you modify a field of a record awk re-compiles the record, separating fields with the value of OFS and stripping leading and trailing blanks from the record. To keep white-space intact you must modify the whole record, not any one field of it.
For example to do what you want with GNU awk would be:
$ echo " foo bar" | awk '{ $0=gensub(/(^\s*\S+\s+).*/,"\\1baz",""); print $0 }'
foo baz
Do NOT think that can just do sub(/bar/,"baz")
as that will fail when "bar" appears earlier in the record than as the 2nd field:
$ echo " rhubarb bar" | awk '{ sub(/bar/, "baz"); print $0 }'
rhubazb bar
$ echo " rhubarb bar" | awk '{ $0=gensub(/(^\s*\S+\s+).*/,"\\1baz",""); print $0 }'
rhubarb baz
In general, to replace the Nth field of a record where the fields are separated by the default FS would be:
$0=gensub(/((^\s*\S+\s+){N-1})\S+/,"\\1baz","")
and for FS values that can't be negated in a character class, this time using GNU awk for the 4th arg to split():
awk -F'<whatever>' '{split($0,f,FS,s); f[2]="baz"; r=s[0]; for (i=i;i<=NF;i++) r=r f[i] s[i]; $0=r; print $0}'
Upvotes: 3
Reputation: 74596
Whenever you "touch" the fields in a record (in this case by assigning to the second field), awk reformats the whole record. So $1
is "foo" and each field is separated by the Output Field Separator OFS
, which is a single space by default.
To keep the line intact, you could change your code to something like this:
$ echo " foo bar" | awk '{ sub(/bar/, "baz"); print $0 }'
baz bar
Operating on the line as a whole, rather than the individual fields, means that the reformatting doesn't take place.
...Although at that point, you may as well be using sed:
$ echo " foo bar" | sed 's/bar/baz/'
baz bar
Upvotes: 4
Reputation: 80921
awk splits lines on spaces.
For that line awk sets $1="foo"
and $2="bar"
.
When you don't modify anything about a line awk just prints the input line back out.
When you do modify the line (by assigning to one of the fields) awk recombines the fields to form the output line (it uses the value of OFS
to recombine the fields).
So awk takes your two fields (now $1="foo"
and $2="baz"
) and does (effectively) this:
printf "%s%s%s\n", $1, OFS, $2
Upvotes: 2