/flags/awk/awk-v-assign-variable
awk -v var=value: pass a shell variable into an awk program
- tool
- awk
- command
- awk
- flag
- -v var=value
- default
- no variables assigned; an unset awk variable is the empty string (0 in arithmetic)
awk -v limit="$LIMIT" '$3 > limit' data.txt copies the shell value into the awk variable limit before the program starts. That is the safe way to use shell variables in awk: the program stays in single quotes, so the shell never edits it, and the value cannot break the program's syntax. Inside the program the variable is written without $; $limit would mean "the field whose number is the value of limit".
Syntax
-v var=value (GNU long form --assign=var=value) can be repeated, one assignment per -v. The assignment happens before the BEGIN block, so the value is available everywhere. It is POSIX, so it works the same in gawk, mawk, BusyBox awk and the BSD/macOS awk.
n=2
echo 'apple 3' | awk -v n="$n" -v unit=kg '{ print $1, $2 * n, unit }'
awk -v 'msg=hello world' 'BEGIN { print msg }'
echo x | awk -v v=early 'BEGIN { print "begin:" v } { print "main:" v }'
echo x | awk 'BEGIN { print "begin:[" v "]" } { print "main:" v }' v=lateOutput
apple 6 kg hello world begin:early main:early begin:[] main:late
The last two lines show the difference with an operand assignment (v=late after the program): it runs only when awk reaches it in the argument list, after BEGIN, so BEGIN sees an empty value.
Escape sequences in the value
The value is processed like an awk string literal: \t, \n and \\ are interpreted. That is handy for separators and wrong for paths:
awk -v sep='\t' 'BEGIN { printf "a%sb\n", sep }' | od -c | head -1
awk -v p='C:\new' 'BEGIN { print p }'
p='C:\new' awk 'BEGIN { print ENVIRON["p"] }'Output
0000000 a \t b \n C: ew C:\new
ENVIRON["name"] reads an exported environment variable without escape processing, so it is the right choice for arbitrary data such as file paths or user input. An unknown escape such as \q produces the escape sequence treated as plain warning.
Ways to get a value into awk
| Method | When it is assigned | Escapes processed | Notes |
|---|---|---|---|
| -v var=value | before BEGIN | yes | POSIX; repeat -v for each variable |
| var=value operand | when awk reaches it among the files | yes | Can change a value between two input files |
| ENVIRON["var"] | any time | no | The variable must be exported (or set on the command line) |
| "$var" spliced into the program | by the shell | n/a | Fragile: quotes or spaces in the value break or alter the program |
Errors
The name must be a valid awk identifier and the argument must contain =:
awk -v 2x=1 'BEGIN { }'Output · exit 2
awk: fatal: `2x' is not a legal variable name
awk -v x without =value makes gawk complain that the argument to -v is not in var=value form, print its usage text and exit 1. Assigning a built-in such as -v FS=, is allowed and is equivalent to -F, (see awk -F).
Numbers
A value that looks like a number compares numerically (POSIX calls it a numeric string), so -v limit=10 with $3 > limit compares 9 > 10 as numbers, not as text. gawk does not treat 0x1A or 010 as hexadecimal or octal in input data unless --non-decimal-data is given; 010 is simply 10.
FAQ
Why does my shell variable not work inside the awk program?
The program is in single quotes, so the shell does not expand $name there, and inside awk $name means a field. Pass the value with -v name="$name" and use name (without $) in the program.
What is the difference between -v x=1 and x=1 after the program?
-v assigns before BEGIN runs. An assignment written among the file operands runs only when awk reaches that position, after BEGIN, so BEGIN sees an empty variable.
How do I pass a value that contains backslashes, such as a Windows path?
-v processes escape sequences, so C:\new becomes C: plus a newline. Export the value and read it with ENVIRON["name"], which awk takes literally.