我正在使用通配符表达式来匹配文件名。
对于普通的非 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
sudo su
在我切换到 root 用户并尝试相同的命令后,发生了以下情况:
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用户使用?
答案1
在/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 -c 'ls /var/log/apache2/*[0-9].gz'
在这种情况下sudo
将运行升高 sh
而这个壳就会成功扩大格局。
(一开始我想sudo -s …
这么做,但是不。
答案2
与 Windows/DOS 不同,在 Unix 系统中,shell 在运行命令之前会扩展 glob。在这种情况下,shell 使用您的 UID 而不是 root 运行,因此它无法读取该目录。
不匹配情况下的默认行为是逐字传递 glob 表达式。 例如如果你ls xyz*xyz
在普通 shell 中运行,你会看到ls: cannot access 'xyz*xyz': No such file or directory
from ls
,因为它将该字符串作为参数。
就像您运行以将文字字符串ls '*'
传递给一样。(删除引号也是 shell 的工作,因此命令无法判断其参数是否被引用。)*
ls
您可以在 bash 中更改此行为,例如,这shopt -s failglob
意味着相同的ls xyz*xyz
命令将给出 bash: no match: xyz*xyz
没有ls
根本无法调用。(如果您使用过sudo
,您会注意到在收到此错误消息之前它并没有提示您输入密码。)
failglob
当尝试读取您没有读取权限的目录时,会产生相同的“不匹配”错误,不幸的是,当 bash 对open
目录进行系统调用时,不会警告您 EPERM 错误。bash: no match: /var/log/private/*
(还有shopt -s nullglob
,其中不匹配的 glob 表达式被删除而不是逐字传递。那么您的sudo ls /...*
命令就会令人困惑地仅作为运行sudo ls
。这可能对于您可能想要执行*.gz *.tgz *.tar
或其他操作的脚本很有用,并且不会因扩展失败而出现错误。可能不是您通常想要用于交互式使用的东西。)
您可以使用shopt -u failglob
或任何方式联合国在 shell 中设置这些选项,如果设置了就尝试一下。