Bash 脚本可从主目录调用,但不能从脚本目录调用

Tri*_*ews 4 bash scripts executable

尝试使脚本可调用时,我遇到了一个非常奇怪的错误。我在 /srv/projectname/scripts 中有一个脚本目录,我在其中存储您知道的脚本,这些脚本将被称为不同项目的 cron 作业。我正在尝试添加一个新的并看到非常奇怪的行为。在调试中,我使用这组命令重现它

从 /srv/projectname/scripts 创建文件 创建文件

vi helloworld.sh
Run Code Online (Sandbox Code Playgroud)

准确插入文本:

#!/usr/bin/env bash

echo "Hello World!"
Run Code Online (Sandbox Code Playgroud)

使脚本可执行并尝试调用它:

chmod +x helloworld.sh
./helloworld.sh
Run Code Online (Sandbox Code Playgroud)

这使:

-bash: ./helloworld.sh: Permission denied
Run Code Online (Sandbox Code Playgroud)

确保没有代码错误:

bash helloworld.sh
Run Code Online (Sandbox Code Playgroud)

这使:

Hello World!
Run Code Online (Sandbox Code Playgroud)

将脚本复制到 home 并调用它:

cp helloworld.sh ~/helloword.sh
~/helloword.sh
Run Code Online (Sandbox Code Playgroud)

这使:

Hello World!
Run Code Online (Sandbox Code Playgroud)

我不知道发生了什么。我已经尝试了很多变体,我给出了完整路径,同样的错误,或者如果我 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
Run Code Online (Sandbox Code Playgroud)

分别

任何帮助都是极好的。

编辑:吉尔斯有答案。为了拯救遇到此问题的任何其他人,请使用谷歌搜索。

sudo mount /srv/projectname/ -o remount
Run Code Online (Sandbox Code Playgroud)

重新加载编辑过的 fstab,一切又正常了。

Gil*_*il' 5

文件权限说它是可执行的,但文件不是可执行的。发生这种情况的原因有三个。

  • 您对文件权限的挖掘不够深入——有一个访问控制列表使您无法执行该文件。您可以使用命令查看文件的 ACL getfacl /path/to/file。这不是这里的情况,因为ls -l表明文件上没有 ACL(+权限末尾会有,例如-rwxr-xr-x+)。
  • 该文件存储在使用该noexec选项装载的卷上。包含usersfstab一行中暗示了此选项(如果您想让文件系统可由用户挂载并允许用户在其上执行文件,请使用noauto,users,exec)。此挂载选项会导致所有常规文件无论权限如何都不可执行。
  • 该文件是一个脚本,它引用了在其 shebang 行中不可执行的解释器,或者是一个动态链接的二进制文件,它引用了一个不可执行的动态加载器。考虑到复制文件会生成一个您可以执行的文件(并且/usr/bin/env无论如何都可以执行),因此情况并非如此。

通过消除过程,该文件位于使用该noexec选项安装的卷上。

唯一的解决方法是:

  • 不要用noexec选项挂载卷。此选项没有安全隐患(与nosuid和不同nodev)。它对于没有执行权限概念的文件系统最有用,您可以在其中选择使所有内容都可执行还是不执行。
  • 在执行之前复制文件。
  • 使用绑定挂载或bindfs创建可执行文件可执行文件系统的视图。
  • 显式调用解释器或动态加载器,例如这里bash helloworld.sh。这不会执行helloworld.sh,它会执行/bin/bashhelloworld.sh.