Consider the following simple shell script:
rm -rf bar \"bar\"
mkdir -p bar
touch bar/baz
echo "bar"/*
I get the expected output with bash, ksh, zsh and dash, but I don't get it with posh:
susam@debian:~$ bash foo.sh
bar/baz
susam@debian:~$ ksh foo.sh
bar/baz
susam@debian:~$ zsh foo.sh
bar/baz
susam@debian:~$ dash foo.sh
bar/baz
susam@debian:~$ posh foo.sh
bar/*
I am trying to understand if the behaviour of posh is correct as per the POSIX standard or if it is a bug.
The relevant section in the POSIX documents seem to be "2.6 Word Expansion":
Both of them mention that pathname expansion occurs before quote removal.
- Pathname expansion (see Pathname Expansion) shall be performed, unless
set -f
is in effect.- Quote removal (see Quote Removal) shall always be performed last.
Considering this, the posh behaviour looks right because "bar"/*
does not literally match any path above before the quote removal, so path expansion does not occur.
So this led me to suspect that if there were a directory literally named "bar"
, i.e. the quotes were part of the directory name, then posh would have matched it. But the following altered script shows that this is not true.
rm -rf bar \"bar\"
mkdir -p \"bar\"
touch \"bar\"/baz
echo "bar"/*
Here is the output:
susam@debian1:~$ bash foo2.sh
bar/*
susam@debian1:~$ ksh foo2.sh
bar/*
susam@debian1:~$ zsh foo2.sh
foo2.sh:3: no matches found: bar/*
susam@debian1:~$ dash foo2.sh
bar/*
susam@debian1:~$ posh foo2.sh
bar/*
So the pattern "bar"/*
in posh matches neither the path bar/baz
nor the path "bar"/baz
. What does it match then? Is the posh behaviour a bug or a feature?
Here are the version details in case it helps you to helps me:
susam@debian:~$ cat /etc/debian_version
8.3
susam@debian:~$ dpkg -l bash ksh zsh dash posh
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-===========================-==================-==================-============================================================
ii bash 4.3-11+b1 amd64 GNU Bourne Again SHell
ii dash 0.5.7-4+b1 amd64 POSIX-compliant shell
ii ksh 93u+20120801-1 amd64 Real, AT&T version of the Korn shell
ii posh 0.12.3 amd64 Policy-compliant Ordinary SHell
ii zsh 5.0.7-5 amd64 shell with lots of features
This is a bug in posh
-- see bug #636601. It is still open as of posh
version 0.12.6.
Attached to the discussion of that bug you'll find a patch. When applying that, posh
behaves similar to bash
(so in your first example echo "bar"/*
gives bar/baz
).
Furthermore, that behaviour of bash
(and patched posh
) does conform to POSIX. The standard says
- Quote removal (see Quote Removal) shall always be performed last.
This is meant literally, as a purely syntactical action to remove protective quotes in the very last step. The semantical meaning of quotes will still apply in earlier steps, as pointed out by hek2mgl. (Otherwise, e.g. a quotation like "*"
would not have any effect at all.)
So on second thought, this conclusion is not correct:
Considering this, the posh behaviour looks right because "bar"/* does not literally match any path above before the quote removal, so path expansion does not occur.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With