what happens when a script is run using 'sh <somescript>'?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
what happens when a script is run using 'sh <somescript>'?
Hi,
what is the difference between running a script using
Code:
$ ./somescript
and
Code:
$ sh somescript
Because when i try to run a script which does not have executable permission using the first method, the shell shows an error. But if i run the script with the same permissions using the second method, it works.
Distribution: debian, gentoo, os x (darwin), ubuntu
Posts: 940
Rep:
./somescritp executes the script (file needs execution perms) the intertpreter is read from the first line (shebang) e.g.: #!/bin/bash
but the first line may contain any interpreter e.g. #!/usr/bin/php4
is perfectly valid too.
sh somescript reads the file contents and executes every line (which does not start with a comment '#')
butwhat happens when there is no #!/bin/bash in the first line?
isnt the execution of the script when we do a './somescript' done by a child shell (after a fork and exec by the current shell)? how different is this from running it by 'sh somescript'? because in this case also, the current shell does a fork and exec to spawn the new 'sh'?
Distribution: debian, gentoo, os x (darwin), ubuntu
Posts: 940
Rep:
without the shebang your current shell tries to interpret every line. so i guess there is no reald diff in running ./somefile or sh somefile
IF:
you use bash as you standard shell - though some people use zsh or i-dont-know-what-else.
so - just in case you always want (or even need) your script to run under bash you use a shebang!
you could even write a script in zsh and the you have a firstline of #!/bin/zsh so that even when you usually run bash you could execute ./somescript which will always be interpreded by zsh :-)
i think you should read through some advanced bash scripting tutorials
without the shebang your current shell tries to interpret every line. so i guess there is no reald diff in running ./somefile or sh somefile
Not quite. The current shell examines the first line of the file, if it is executable, and if it finds a suitable shebang line, it launches the specified interpretter as a child process, and gives that interpretter the filename as an argument. This is exactly the same as you entering that command as a commandline, and having the shell execute it. There is a third style of invoking a shell script, called 'sourcing' the script. In that case, the specified script is read and interpetted as if you were typing the contents of the script in real time. There is no child shell launched. The beauty of this method is that environment variables can be set, and do not disappear after the child shell terminates ('cause there isn't one). Sourcing the script can be done with the 'source' command:
With ./script you'll get an error (bash: ./script: Permission denied) and you'll need to add execution permissions: chmod +x script and then try again.
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
Rep:
Quote:
Originally Posted by theNbomr
Not quite. The current shell examines the first line of the file, if it is executable, and if it finds a suitable shebang line, it launches the specified interpreter as a child process, and gives that interpreter the filename as an argument. This is exactly the same as you entering that command as a commandline, and having the shell execute it.
This is not exactly what happens.
The current shell doesn't look for a shebang in the script, not does it care that much about if the file is executable.
It just forks, then pass the name of the command to the kernel, through one of the exec family system calls.
If the file has a shebang on its beginning, then the kernel launch the interpreter that follows the shebang and the forked shell is replaced by this interpreter.
If the script lack the shebang, then the exec call fails because the file hasn't a known executable format, despite the execute permission.
The control comes back to the forked shell, which either interpret itself the script if the launching is bourne shell compatible, or use a sh compatible shell to run the script if it isn't, like csh, zsh, ...
I've just spent some time studying the bash man-page; in particular, the section 'COMMAND EXECUTION'.
To my surprise, you are quite right that the shell (bash, at least) interprets a script that does not contain a leading shebang. However, the bash man-page suggests that the shell does indeed look for a shebang line, and upon finding one, launches (fork + exec, as you detailed) the specified interpretter. The man page also explains that the filesystem is searched along each directory in $PATH for 'executable files'. My assumption was that it understands a file to be 'executable' based upon the permission level of the file, and not by it's binary object format. Am I wrong about that?
At any rate, it seems to me that the shell does care about shebangs and executable status.
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
Rep:
Quote:
Originally Posted by theNbomr
jlliagre:
I've just spent some time studying the bash man-page; in particular, the section 'COMMAND EXECUTION'.
To my surprise, you are quite right that the shell (bash, at least) interprets a script that does not contain a leading shebang. However, the bash man-page suggests that the shell does indeed look for a shebang line, and upon finding one, launches (fork + exec, as you detailed) the specified interpretter. The man page also explains that the filesystem is searched along each directory in $PATH for 'executable files'. My assumption was that it understands a file to be 'executable' based upon the permission level of the file, and not by it's binary object format. Am I wrong about that?
The loader, not the shell, looks for the binary object format and the shebang is also a binary "magic number" that is accepted by one of the handlers (binfmt_script on Linux).
Quote:
At any rate, it seems to me that the shell does care about shebangs and executable status.
Nope, the shell doesn't even know about what a shebang is, it's just a comment for that matter.
i am still a bit confused . since fork+exec is done in both cases, how different is the fork+exec in the first case (when doing a ./somescript) from the fork+exec when we do a 'sh somescript'? how can the shell in the latter case execute the script even if it has no 'x' permission?
Yes the post by jlliagre is right.
When you "sh some_script", the shell only reads the script, so it doesn't matter if execute permission is there or not. So to be exact, only read permission is "necessary", execute permission is fine but it doesn't matter.
The exec() class of calls handles the shebang all on its own without the help of the shell.
Okay, that is making it more clear. The bash man-page talks about finding executable files in $PATH, but that is only for the purpose of searching. Once found or unambiguously specified, then the execute permission is irrelevent.
I'm sorry, I probably wasn't very clear. I was only referring to what happens when you "sh some_script". In bash, when you type "sh some_script" the PATH is searched to find the "sh" executable only, because an absolute path wasn't specified in my example cmdline. Then the argument "some_script" is passed to that program "/bin/sh" because that's where it was found in the PATH. /bin/sh is executed via fork()/exec() by the current shell that is parsing your command line. /bin/sh in turn opens the file some_program for reading.
When you specify ./some_script doesn't involve PATH either in that case because you are specifying an absolute path (well relative actually).
bash tries to fork() and exec() it directly but only if its executable, and then the kernel examines the shebang if that is what it is.
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
Rep:
Actually, the execute permission is still required for the execve system call to succeed, my point is it isn't sufficient, a valid magic number being another requirement.
Execute permission is ignored when the script is passed as a shell argument, or read from the shell stdin.
Edit: bash doesn't care about the execute flag, and try the execve anyway, just in case ...
Thanks jlliagre, I meant to say that.
I really wasn't completely sure if bash checked or not before passing it to exec(), in theory at least it could avoid the "for sure" error that would result from calling exec() on an argument that does not have execute permission... but again whatever it really does it will fail like you said without it.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.