I'm confused about execute file permissions not behaving as I expect. Probably because my expectations are wrong. Anyway:
I have a script file, for simplicity is just called s
, located in ~/bin
. For the sake of this example, the file contains just the following lines:
#!/bin/zsh
echo "Test";
Very simple.
I navigate to the ~/bin
directory, and chmod
the file permissions of s
to 400
– i.e., read-only for me only. No execute permission. So then I try executing the script by entering its path, giving this:
% ./s
zsh: permission denied: ./s
So far so good. The file can't be executed due to the wrong permissions. Bumping permissions up to 500
(execute permission granted) works fine too – with these permissions, the file executes fine:
% ./s
Test
This is all as expected. But then I chmod
permissions back down to 400
(execute permission off again), try source
ing the file, and this happens:
% source s
Test
Although permissions are 400
, the script executes.
So here's my question: why does ./s
fail (like it should) but source s
executes normally? Doesn't this defeat the whole purpose of the execute permission?
At 400
permissions, sh s
and zsh s
also work.
I'm sure I'm either doing or understanding something horribly wrong somewhere. Can someone point out where to me, and explain the difference between ./s
, source s
, sh s
and zsh s
?
Best Answer
When you run
./s
, you tell the kernel to execute the programs
. If you have execution permission, then the kernel reads the first few bytes of the file, sees the#!
line so it knows that this is a script, and runs the interpreter, passing it the script name as its first argument. If you don't have execute permission, the kernel aborts the execution at the first step.When you run
zsh s
, you executezsh
, and tell it to read the file calleds
and interpret it as commands. You aren't executings
, you're executingzsh
. Same thing withsh s
orcat s
.When you run
source s
, again, you tell zsh to read a file, so what matters is that you have read permission on it.