[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Bash test builtin fails on: test -n '>' -a 1 -eq 1
From: |
Chet Ramey |
Subject: |
Re: Bash test builtin fails on: test -n '>' -a 1 -eq 1 |
Date: |
Tue, 22 Oct 2024 10:22:33 -0400 |
User-agent: |
Mozilla Thunderbird |
On 10/22/24 3:34 AM, cirrus.mazurka-0t@icloud.com wrote:
The following produces a `bash: test: too many arguments` exception in `test`,
with exit status 2:
``` bash
v='>'
test -n "$v" -a yes '!=' no # bash: test: too many arguments
echo $? # 2
test -n '>' -a 1 -eq 1 # bash: test: too many arguments
echo $? # 2
[ -n '>' -a 1 -eq 1 ] # bash: [: too many arguments
echo $? # 2
[[ -n '>' -a 1 -eq 1 ]]
# bash: syntax error in conditional expression
# bash: syntax error near `-a'
echo $? # 2
```
It works without the -a, and as such, it works using && instead of the -a:
```
v='>'
test -n "$v"
echo $? # 0
[ -n "$v" ]
echo $? # 0
test -n "$v" && test yes '!=' no
echo $? # 0
[ -n "$v" ] && [ yes '!=' no ]
echo $? # 0
```
There is no mention of this peculiar behaviour inside the documentation:
https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-test
Since there are five or more arguments, bash parses and evaluates the
expression using the historical operator precedence algorithm instead of
the POSIX test algorithm, which works on the number of arguments. POSIX
leaves the behavior with 5 or more arguments unspecified, and removes the
-a and -o binary operators completely.
The historical algorithm gave binary operators like `>' greater precedence
than any of the unary operators.
Known versions affected:
GNU bash, version 5.2.37(1)-release (x86_64-apple-darwin22.6.0)
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin22)
If this is intended behaviour, then what is the suitable workaround?
1. Should I always use `&&` instead of `-a`?
Yes. The documentation for coreutils `test' already says this, POSIX says
the same thing, the current bash devel man page says
"The historical operator-precedence parsing with 4 or more argu-
ments can lead to ambiguities when it encounters strings that
look like primaries. The POSIX standard has deprecated the -a
and -o primaries and enclosing expressions within parentheses.
Scripts should no longer use them. It's much more reliable to
restrict test invocations to a single primary, and to replace
uses of -a and -o with the shell's && and || list operators."
Plus it has the advantage of short-circuiting evaluation, which test does
not do.
2. Should I use a parameter replacement? e.g. `test -n "${v//>/.}" -a 1 -eq 1`
You shouldn't use -a to compose expressions at all.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU chet@case.edu http://tiswww.cwru.edu/~chet/