我在尝试使脚本可调用时遇到了一个非常奇怪的错误。我在 /srv/projectname/scripts 中有一个脚本目录,我在其中存储了要作为不同项目的 cron 作业调用的脚本。我尝试添加一个新的脚本,但看到了非常奇怪的行为。在调试中,我使用这组命令重现了它
从 /srv/projectname/scripts 创建一个文件 创建一个文件
vi helloworld.sh
准确插入文本:
#!/usr/bin/env bash
echo "Hello World!"
使脚本可执行并尝试调用它:
chmod +x helloworld.sh
./helloworld.sh
这使:
-bash: ./helloworld.sh: Permission denied
确保没有代码错误:
bash helloworld.sh
这使:
Hello World!
将脚本复制到主目录并调用它:
cp helloworld.sh ~/helloword.sh
~/helloword.sh
这使:
Hello World!
我不知道发生了什么。我尝试了很多方法,我给出了完整路径,但还是出现同样的错误,或者如果我使用 sudo,则不会出现错误,但也不会打印“Hello World!”。
其他详细信息:运行于:Ubuntu 12.04.4 LTS 我还注意到,我无法使用制表符完成出现此错误的脚本的全名,但一旦我移动它,我就可以了。目录 /srv/projectname 是一个 git repo,但尚未将此脚本添加到其中,因为我通常只在它工作后才这样做。
脚本和脚本目录的 ls -l 行是
-rwxrwxr-x 1 ubuntu ubuntu 41 Apr 21 20:25 helloworld.sh
drwxrwxr-x 3 ubuntu ubuntu 4096 Apr 21 20:25 scripts
分别
任何帮助都是极好的。
编辑:Gilles 有答案。为了节省遇到此问题的其他人的谷歌搜索时间。
sudo mount /srv/projectname/ -o remount
重新加载编辑的 fstab,一切都恢复正常。
答案1
文件权限表明它是可执行的,但该文件却不可执行。有三个原因可能导致这种情况发生。
- 您没有深入研究文件权限 — 有一个访问控制列表使该文件对您不可执行。您可以使用命令 查看文件的 ACL
getfacl /path/to/file
。但这里的情况并非如此,因为显示该文件没有 ACL(权限末尾ls -l
会有,例如)。+
-rwxr-xr-x+
- 文件存储在使用 选项挂载的卷上。此选项由一行中的
noexec
表示(如果您希望使文件系统可由用户挂载并允许用户在其上执行文件,请使用)。此挂载选项使所有常规文件无论其权限如何都不可执行。users
fstab
noauto,users,exec
- 该文件是一个脚本,它引用了其 shebang 行中不可执行的解释器,或是一个动态链接二进制文件,它引用了不可执行的动态加载器。这里的情况并非如此,因为复制文件会产生一个可以执行的文件(而且
/usr/bin/env
无论如何都是可执行的)。
通过排除过程,该文件位于使用该noexec
选项安装的卷上。
唯一的解决方法是:
- 不要使用
noexec
选项挂载卷。此选项没有安全隐患(与nosuid
和nodev
不同)。它主要用于没有执行权限概念的文件系统,您可以在其中选择使所有内容可执行或不执行任何操作。 - 执行文件之前先复制它。
- 使用绑定安装或绑定文件系统创建可执行文件可执行的文件系统视图。
- 显式调用解释器或动态加载器,例如此处
bash helloworld.sh
。这不会执行helloworld.sh
,而是执行/bin/bash
从中读取的内容helloworld.sh
。