1

From bash manual:

3.7.2 Command Search and Execution

After a command has been split into words, if it results in a simple command and an optional list of arguments, the following actions are taken.

...

  1. If the name is neither a shell function nor a builtin, and contains no slashes, Bash searches each element of $PATH for a directory containing an executable file by that name.

  2. If the search is successful, or if the command name contains one or more slashes, the shell executes the named program in a separate execution environment. Argument 0 is set to the name given, and the remaining arguments to the command are set to the arguments supplied, if any.

  3. If this execution fails because the file is not in executable format, and the file is not a directory, it is assumed to be a shell script and the shell executes it as described in Section 3.8 [Shell Scripts], page 39.

  1. Suppose a bash script myscript doesn't contain a shebang.

    • Does the quote mean that if the script is executed in bash via command myscript, then

      • bash will first assume it is an ELF and calls execve() on it, and because it is a bash script not ELF, execve() call will fail,

      • bash will next execute bash myscript?

    • Compared to running a bash script via bash myscript in bash, running the script via myscript in bash will additionally have a failure call to execve() on the script directly?

    • If yes, is myscript slower than bash myscript? Why does "A Practical Guide to Linux Commands, Editors, and Shell Programming By Mark G. Sobell" say the opposite?

      Although you can use bash to execute a shell script, this technique causes the script to run more slowly than giving yourself execute permission and directly invoking the script.

  2. If a bash script myscript contains a shebang #! /bin/bash, when it is executed in bash via command myscript,

    • is it executed in the same way as it is executed in bash via command bash myscript?

    • is it executed in the same way as the shebang were removed from the script and then the script were executed via command myscript ?

Thanks.

My post is inspired by How is running a script like an executable different from running it by a shell explicitly? and Which shell interpreter runs a script with no shebang?

    1 Answer 1

    4
      • Does the quote mean that if the script is executed in bash via command myscript, then

        • bash will first assume it is an ELF and calls execve() on it, and because it is a bash script not ELF, execve() call will fail,

        If Bash finds an executable file, it will first assume that it is in some format the operating system can execute and call execve on it. In the event that that succeeds, this still might not be an ELF or other native executable file. For example, Linux's binfmt_misc feature allows many other executable formats to run. In this particular case, the execve call will most likely fail.

        • bash will next execute bash myscript?

        Bash will use its existing subprocess to execute the script within it, reinitialising the shell environment as necessary. There is not an additional process launched or exec call.

      • Compared to running a bash script via bash myscript in bash, running the script via myscript in bash will additionally have a failure call to execve() on the script directly?

        Yes, I suppose so, if you mean "a failed call".

      • If yes, is myscript slower than bash myscript? Why does "A Practical Guide to Linux Commands, Editors, and Shell Programming By Mark G. Sobell" say the opposite?

        Although you can use bash to execute a shell script, this technique causes the script to run more slowly than giving yourself execute permission and directly invoking the script.

        Mindful of prevailing libel laws, I won't comment on the second part of that question, but even several failed library & system calls are not going to make a measurable difference compared to the launch of an entire bash process and then interpreting a script. I can't access the page in question to find any context you might have missed out. It almost certainly isn't discussing the shebangless case, however.

    1. If a bash script myscript contains a shebang #! /bin/bash, when it is executed in bash via command myscript,

      • is it executed in the same way as it is executed in bash via command bash myscript?

      Yes; in one case, bash myscript is execed directly by the subprocess, and in the other the system execs /bin/bash myscript once it finds the shebang line.

      • is it executed in the same way as the shebang were removed from the script and then the script were executed via command myscript ?

      In so far as you can reasonably detect, yes. None of this matters. Strictly, the main() function of bash doesn't run again in this case, because the subprocess just reinitialises itself internally, and it does run in the other situation. You could construct a scenario where this matters if you were really keen, but it isn't worth the effort.

    Note that this is a Bash functionality, and other shells execute shebangless scripts with sh or some other shell, rather than either bash or themselves, as noted in the other question you linked. We're also assuming that your interactive shell is the same bash as the one in your shebang lines.

    4
    • Thanks. When a call to execve() finishes, does execve() terminate its process, regardless whehter execve() succeeds or fails? I thought yes, so when execve() fails to execute a shell script, it would terminate the subprocess, and the original shell will have to fork a subprocess to execute the script.
      – Tim
      CommentedApr 23, 2018 at 12:27
    • No, it doesn’t.CommentedApr 23, 2018 at 18:57
    • Thanks.When a bash script ./test.sh with shebang #! /bin/bash is executed via command ./test.sh, is it actually executed as /bin/bash ./test.sh? If yes, is it correct to expect bash to run execve("/bin/bash", ["/bin/bash", "./test.sh"], ...) = 0? But I run strace -f ./test.sh 2>&1 | less, and only find one call to execve(): execve("./test.sh", ["./test.sh"], [/* 59 vars */]) = 0. Note the difference in the first argument, which is for the executable file.
      – Tim
      CommentedApr 23, 2018 at 21:14
    • @Tim, see What exactly happens when I execute a file in my shell.CommentedApr 24, 2018 at 4:17

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.