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
- You need a login shell: I tried login and interactive shells, both did not resolve the issue. I now changed the question so this is already included in the examples.
- You should not escape the variable: If I do not escape the variable, the command prints something, but not what I want. Please have a look at the first code box in my question. It lists two variants of calling the command. I want the second type of output, not the first. I also thought that
$
might be the wrong way of escaping$
, so I tried with 2, 3, or 4 backslashes without success. - The variable is not known in the nested shell: I tried
bash -c env
and it showed the variable. - This is related to your environment: I tried to exclude this option by also testing inside a clean docker container.
> 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/"'
23
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/"'
(https://savannah.gnu.org/support/index.php?111125)