With GNU awk
5.3.1 I want to assign a default value to a variable if it has not been given one on the command line. The value can be anything, including 0. I thought I could use SYMTAB
but as SYMTAB
is built during the parsing and before the execution it does not work:
$ awk -v v=1 'BEGIN { if(!("v" in SYMTAB)) v = 42; print "v = " v }' /dev/null
v = 1
$ awk 'BEGIN { if(!("v" in SYMTAB)) v = 42; print "v = " v }' /dev/null
v =
Is there another way?
With GNU awk
5.3.1 I want to assign a default value to a variable if it has not been given one on the command line. The value can be anything, including 0. I thought I could use SYMTAB
but as SYMTAB
is built during the parsing and before the execution it does not work:
$ awk -v v=1 'BEGIN { if(!("v" in SYMTAB)) v = 42; print "v = " v }' /dev/null
v = 1
$ awk 'BEGIN { if(!("v" in SYMTAB)) v = 42; print "v = " v }' /dev/null
v =
Is there another way?
Share Improve this question edited Feb 10 at 13:53 Renaud Pacalet asked Feb 10 at 12:37 Renaud PacaletRenaud Pacalet 29.4k3 gold badges41 silver badges59 bronze badges 03 Answers
Reset to default 5The way to determine if a variable is set or not in any awk is by comparing it to both 0
and null
since the initial value for any scalar variable is 0-or-null
, there's no need for a gawk-specific SYMTAB[]
lookup (which you've already discovered you can't use for this as the variable v
will exist in SYMTAB[]
since it's mentioned in your code) or typeof()
call. For example:
$ awk -v v=1 'BEGIN { if((v=="") && (v==0)) v = 42; print "v = " v }'
v = 1
$ awk -v v=0 'BEGIN { if((v=="") && (v==0)) v = 42; print "v = " v }'
v = 0
$ awk -v v= 'BEGIN { if((v=="") && (v==0)) v = 42; print "v = " v }'
v =
$ awk 'BEGIN { if((v=="") && (v==0)) v = 42; print "v = " v }'
v = 42
FWIW that's also how you can tell if an optional parameter to a function was passed in or not.
By the way, in addition to portability, there's a functional difference between the above approach and using gawk for typeof(v) == "untyped"
as suggested elsewhere:
$ awk 'BEGIN { print "v = " v; if((v=="") && (v==0)) v = 42; print "v = " v }' /dev/null
v =
v = 42
$ awk 'BEGIN { print "v = " v; if(typeof(v) == "untyped") v = 42; print "v = " v }' /dev/null
v =
v =
If you're going to use typeof()
for this then you need to check for its output being either untyped
or unassigned
:
$ awk 'BEGIN { print "v = " v; if(typeof(v) ~ /^un(typed|assigned)$/) v = 42; print "v = " v }' /dev/null
v =
v = 42
See the gawk man page for more information on that :-).
I would exploit typeof
function for this task following way
awk -v v=1 'BEGIN{print typeof(v)=="untyped"?"v was not given":"v was given"}' /dev/null
awk 'BEGIN{print typeof(v)=="untyped"?"v was not given":"v was given"}' /dev/null
gives output
v was given
v was not given
(tested in GNU Awk 5.3.1)
If you want a generic method to differentiate between ...
[ A ] The special
awk
NULL
value (both0
and""
)
[ B ] A string-only empty string (
""
),[ C ] A numeric-only zero (
0
/-0
), or
[ D ] None of the above
... that works across all awk
variants by eliminating dependencies for typeof()
and/or SYMTAB[]
, you can use this reverse waterfall function I conjured up :
function differentiate_zero_null(_) {
return (!!_) ? "D.[" (_) "]-boolean-TRUE" \
: (_ != (_)_) ? "C.<" (_) ">-numeric-zero" \
: (_ < _) != _ ? "B.{" (_) "}-empty-str" \
: "A.(" (_) ")-AWK-NULL"
}