If I call compgen
on bash directly with an environment variable pointing to a directory, it completes paths inside that directory. This can include environment variables if they are no resolved before calling compgen
.
> cd /tmp
> mkdir files
> touch files/aa files/ab
> export MY_FILES=/tmp/files
> echo "$MY_FILES/"
/tmp/files
> compgen -v -A file -- "$MY_FILES/" # not what I want
/tmp/files/ab
/tmp/files/aa
> echo "\$MY_FILES/"
$MY_FILES/
> compgen -v -A file -- "\$MY_FILES/" # this is what I want
$MY_FILES/ab
$MY_FILES/aa
This works fine when I execute the command but doesn't work when the command is called indirectly (not even in a login shell)
> bash -ilc 'echo "\$MY_FILES/"; compgen -v -A file -- "\$MY_FILES/"'
$MY_FILES/
> echo $?
1
You can tell from the echo
command that the escaping works as intended, so this is not an issue with how the string is escaped.
Likewise, putting the line in a script and calling the script doesn't work:
> cat run-compgen
#!/bin/bash -il
echo "\$MY_FILES/"
compgen -v -A file -- "\$MY_FILES/"
echo $?
> ./run-compgen
$MY_FILES/
1
Unsuccessful Solutions
\$
might be the wrong way of escaping $
, so I tried with 2, 3, or 4 backslashes without success.bash -c env
and it showed the variable.> docker run -it ubuntu bash # start a clean Ubuntu container.
# Then inside the container:
> cd /tmp
> mkdir files
> touch files/aa files/ab
> export MY_FILES=/tmp/files
> bash -ilc 'compgen -v -A file -- "\$MY_FILES/"'
This was fixed in bash 5.3. The temporary solution is to call bind
at the beginning of the command, which works with any shell (login, interactive, normal) but generates a warning unless used with an interactive shell:
bash -ic 'bind; compgen -v -A file -- "\$MY_FILES/"'