Why can't the wildcard expression be used as a non-root user?
In /var/log/apache2/*[0-9].gz
the substring *[0-9]
is handled by the pathname expansion mechanism of the shell. Not of sudo
nor ls
. Of the shell. This happens before sudo
or ls
even starts.
To expand /var/log/apache2/*[0-9].gz
the shell needs to examine the content of /var/log/apache2/
. In my Debian 10 the permissions are rwxr-x---
, the ownership is root:adm
. In effect the root's shell can examine the content but a regular user's shell cannot.
Therefore the pattern gets expanded for root, but it stays verbatim for a regular user. Neither sudo
nor ls
expand the pattern and eventually the regular user's (elevated) ls
tries to list information about /var/log/apache2/*[0-9].gz
exactly; there is no such file or directory.
This should work for a regular user:
sudo sh -c 'ls /var/log/apache2/*[0-9].gz'
In this case sudo
will run elevated sh
and this shell will successfully expand the pattern.
(At first I thought sudo -s …
would do it, but no.)
Unlike Windows/DOS, globs are expanded by the shell before running the command in Unix systems. The shell in this case is running with your UID, not root, so it can't read that directory.
The default behaviour in the no-match case is to pass on the glob expression literally. e.g. if you run ls xyz*xyz
in your normal shell, you'll see ls: cannot access 'xyz*xyz': No such file or directory
from ls
, because it got that string as an argument.
Just like if you'd run ls '*'
to pass *
as a literal string to ls
. (Quote-removal is also the shell's job, so a command can't tell whether its arg was quoted or not.)
You can change this behaviour in bash, e.g. shopt -s failglob
means the same ls xyz*xyz
command will give bash: no match: xyz*xyz
without invoking ls
at all. (If you'd used sudo
, you would have noticed that it didn't prompt you for a password before getting this error message.)
failglob
produces the same "no match" error when trying to read a directory that you don't have read permission on, unfortunately not warning you about the EPERM error that bash go when it made an open
system-call on the directory. bash: no match: /var/log/private/*
(There's also shopt -s nullglob
, where a non-matching glob expression is removed instead of passed on literally. Then your sudo ls /...*
command would have confusingly just run as sudo ls
. This is perhaps useful for scripting where you might want to do *.gz *.tgz *.tar
or something, and not get errors from the failed expansion. Probably not something you'd usually want for interactive use.)
You can use shopt -u failglob
or whatever to unset these options in a shell, if you set them to try them out.