1

I want to make an exclusive or in bash. When I define variables a and b, I can use this:

> a=1
> b=
> [ -z "$b" -a "$a" -o "$b" -a -z "$a" ] && echo yes
yes

However, when I try the same construction with the shell variables I'm actually interested in, it fails:

> [ -z "$BASH_ARGV" -a "$@" -o "$BASH_ARGV" -a -z "$@" ] && echo sourced
bash: [: argument expected

What's going on?

drevicko
  • 14,382
  • 15
  • 75
  • 97
  • 1
    If you just want to see if the number of arguments is nonzero, just look at `$#`. No need to look at `$@`'s actual value if the number of entries it contains is all you care about. – Charles Duffy Mar 21 '14 at 00:57

2 Answers2

2

"$@" expands to individual words. You want either "$*" or $# -gt 0

With that "or" in the middle, you probably want:

[ -z "$BASH_ARGV" -a "$*" ] || [ "$BASH_ARGV" -a -z "$*" ]

Or, use the bash-specific

[[ (-z "$BASH_ARGV" -a "$*") || ("$BASH_ARGV" -a -z "$*") ]]

Nevermind: -a has higher priority than -o

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • I usually just use `$1`. Yes, technically it could be the empty string, but that's extremely unlikely to happen by accident. – kojiro Mar 21 '14 at 00:40
2

"$@" expands to one "word" per script argument, which means that it will expand to nothing if there are no script arguments. On the other hand, "$BASH_ARGV" expands to the first value in the array $BASH_ARGV if that array exists and otherwise empty. So I'm not sure what you actually want to compare.

But the main point is that "$@" expands to zero or more words. If it doesn't expand to a single word, then your expression is going to be syntactically incorrect. (Probably. It's possible that the entire set of arguments happens to be a valid expression.)

If you wanted to concatenate all the arguments together, you should use "$*". But that's still not comparable to "$BASH_ARGV". It's not really comparable to "${BASH_ARGV[*]}" either, but the latter would be somewhat more similar.

You might want to check out BASH_ARGC, too.

rici
  • 234,347
  • 28
  • 237
  • 341
  • I only care if `BASH_ARGV` is empty or not. [I'm trying to determine if a script is run with `source` or in it's own shell.](http://stackoverflow.com/questions/3664225/determining-whether-shell-script-was-executed-sourcing-it) It's not a robust test (depends on how the current shell was launched), but it's just for me to use, and works in the situations I want to use it. – drevicko Mar 21 '14 at 00:46