In Bash, it does work since Bash 5.1, but in earlier versions it just silently fails. (It also works in zsh.)
$ ./bash-5.1/bash -c 'set -- aa bb; for i in 1 2 3;
do [ -v $i ] && echo y || echo n; done'
y
y
n
The CHANGES file in the source mentions this change for 5.1-alpha:
3. New Features in Bash
...
x. `test -v N' can now test whether or not positional parameter N is set.
Anyway, there's a bit of a hair-splitting difference between variables and parameters.
Bash's reference manual defines them like this:
A parameter is an entity that stores values. It can be a name
, a number, or one of the special characters listed below. A variable is a parameter denoted by a name
.
And a name
is defined as
A word
consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. Names
are used as shell variable and function names. Also referred to as an identifier
.
So all variables are parameters, but not all parameters are variables. And test -vvarname
returns
True if the shell variable varname is set
So, technically speaking, it's not even documented to work for anything but real variables. Even if it now works for the positional parameters too, the documentation still appears to only mention variables.
In any case, we can use the "alternate value" parameter expansion ${1+x}
and a test for an empty string for $1
and any other parameter (including any variables.) ${par+value}
expands to the given string value
if the parameter is set (even if it's set but empty), and otherwise it expands to the empty string.
$ bash -c 'set -- aa bb; [ ${1+x} ] && echo y || echo n'
y
This should work in all versions of Bash, and in any standard shell.
[ $x ]
test fail to pass when either the parameter is not set or its value is""
? – Tim Jan 27 '18 at 17:07[ ${param+x} ]
tests for a set parameter,[ ${param:+x} ]
tests for a set parameter with a nonempty value (but that's not nearly as useful, since you could just use[ -n "$param" ]
in that case). Bash's manual mentions that a bit in passing, but the standard has a nice table of all those. – ilkkachu Jan 27 '18 at 17:12$argv
array variables (like in csh) and like in csh, zsh arrays are proper arrays. So1
is likearg[1]
. And you can do1=foo
like you can doargv[1]=foo
. – Stéphane Chazelas Feb 08 '24 at 20:13