Bash script callable from home but not scripts directory
I'm having a very weird error when trying to make a script callable. I have a scripts directory in /srv/projectname/scripts where I store you know scripts to be called as cron jobs for different projects. I'm trying at add a new one and seeing very weird behavior. In debugging I reproduce it using this set of commands
from /srv/projectname/scripts create a file create a file
vi helloworld.sh
insert text exactly:
#!/usr/bin/env bash
echo "Hello World!"
Make the script executable and try to call it:
chmod +x helloworld.sh
./helloworld.sh
Which gives:
-bash: ./helloworld.sh: Permission denied
Make sure there isn't a code error:
bash helloworld.sh
Which gives:
Hello World!
Copy the script to home and call it:
cp helloworld.sh ~/helloword.sh
~/helloword.sh
Which gives:
Hello World!
I have no idea what is going on. I have tried a lot of variants where I give the full path, same error, or if I sudo which gives no error, but also doesn't print "Hello World!".
Other details: Running on: Ubuntu 12.04.4 LTS I have also noticed that I can't tab-complete to the full name of a script that gives me this error, but I can once I have moved it. The directory /srv/projectname is a git repo but this script hasn't been added to it yet, I because I usually only do that once its working yet.
ls -l lines for the script and scripts directory are
-rwxrwxr-x 1 ubuntu ubuntu 41 Apr 21 20:25 helloworld.sh
drwxrwxr-x 3 ubuntu ubuntu 4096 Apr 21 20:25 scripts
respectively
Any help would be awesome.
EDIT: Gilles had the answer. To save anyone else who has this problem a google search.
sudo mount /srv/projectname/ -o remount
reloads the edited fstab, and everything works again.
Solution 1:
The file permissions say that it is executable, yet the file is not executable. There are three reasons why this can happen.
- You didn't dig deep enough into the file permissions — there is an access control list that makes the file non-executable to you. You can see a file's ACL with the command
getfacl /path/to/file
. This is not the case here sincels -l
shows that there is no ACL on the file (there would be a+
at the end of the permissions, e.g.-rwxr-xr-x+
). - The file is stored on a volume that is mounted with the
noexec
option. This option is implied by havingusers
in anfstab
line (if you want to make a filesystem user-mountable and to allow users to execute files on it, usenoauto,users,exec
). This mount option causes all regular files to be non-executable regardless of their permissions. - The file is a script that references an interpreter that isn't executable in its shebang line, or a dynamically-linked binary that references a dynamic loader that isn't executable. This isn't the case here given that copying the file results in a file that you can execute (and
/usr/bin/env
is executable anyway).
By a process of elimination, the file is on a volume mounted with the noexec
option.
The only workarounds are:
- Don't mount the volume with the
noexec
option. This option has no security implications (unlikenosuid
andnodev
, which do). It is mostly useful for filesystems with no notion of execute permissions, where you get to choose between making everything executable or nothing. - Copy the file before executing it.
- Use a bind mount or bindfs to create a view of the filesystem where executable files are executable.
- Invoke the interpreter or dynamic loader explicitly, e.g. here
bash helloworld.sh
. This doesn't executehelloworld.sh
, it excecutes/bin/bash
which reads fromhelloworld.sh
.