我正在使用通配符表达式来匹配文件名。
这就是普通的非 root 用户会发生的情况:
debian@MiWiFi-R3-srv:~$ sudo ls /var/log/apache2/*[0-9].gz
ls: cannot access '/var/log/apache2/*[0-9].gz': No such file or directory
这就是我切换到 root 用户sudo su
并尝试相同的命令后发生的情况:
root@MiWiFi-R3-srv:/home/debian# ls /var/log/apache2/*[0-9].gz
/var/log/apache2/access.log.10.gz /var/log/apache2/error.log.10.gz
/var/log/apache2/access.log.11.gz /var/log/apache2/error.log.11.gz
/var/log/apache2/access.log.12.gz /var/log/apache2/error.log.12.gz
为什么这个通配符表达式可以用作root
,但不能用作普通的非 root 用户?
/var/log/apache2/*[0-9].gz
子字符串中的子字符串由*[0-9]
shell 的路径名扩展机制处理。不属于sudo
也不ls
。的壳。这发生在sudo
甚至ls
开始之前。要扩展
/var/log/apache2/*[0-9].gz
shell 需要检查/var/log/apache2/
. 在我的 Debian 10 中,权限是rwxr-x---
,所有权是root:adm
。实际上,root 的 shell 可以检查内容,但普通用户的 shell 不能。因此,该模式针对 root 用户进行了扩展,但对于普通用户来说却是逐字记录的。既不
sudo
也不ls
扩展模式,最终普通用户(提升)ls
尝试/var/log/apache2/*[0-9].gz
准确列出有关信息;没有这样的文件或目录。这应该适用于普通用户:
在这种情况下
sudo
,将运行提升sh
,此 shell 将成功扩展模式。(起初我以为
sudo -s …
会这样做,但没有。)与 Windows/DOS 不同,glob 在 Unix 系统中运行命令之前由 shell 扩展。在这种情况下,shell 使用您的 UID 而非 root 运行,因此它无法读取该目录。
不匹配情况下的默认行为是按字面传递 glob 表达式。 例如,如果您
ls xyz*xyz
在普通 shell 中运行,您会看到ls: cannot access 'xyz*xyz': No such file or directory
fromls
,因为它以该字符串作为参数。就像您运行
ls '*'
以将*
文字字符串传递给ls
. (引号删除也是 shell 的工作,因此命令无法判断其 arg 是否被引用。)您可以在 bash 中更改此行为,例如
shopt -s failglob
意味着相同的ls xyz*xyz
命令将bash: no match: xyz*xyz
完全不调用ls
。(如果您使用过sudo
,您会注意到在收到此错误消息之前它没有提示您输入密码。)failglob
尝试读取您没有读取权限的目录时会产生相同的“不匹配”错误,遗憾的是没有警告您 bashopen
在目录上进行系统调用时出现的 EPERM 错误。bash: no match: /var/log/private/*
(还有,其中不匹配的glob
shopt -s nullglob
表达式被删除而不是按字面传递。然后你的sudo ls /...*
命令会令人困惑地运行为扩展失败。可能不是您通常想要的交互式使用。)sudo ls
*.gz *.tgz *.tar
如果您将它们设置为试用,您可以使用
shopt -u failglob
或其他任何方式在 shell 中取消设置这些选项。