Shell script working fine without shebang line? Why? [duplicate] - linux

This question already has answers here:
Bash script execution with and without shebang in Linux and BSD
(2 answers)
Closed 8 years ago.
I was writing a simple shell script and found out that my shell script doesn't require shebang line
#!/bin/sh
If I give execute permissions to my script and execute using ./myscript.sh. It runs fine.
I am using bash shell and /bin/sh is actually pointing to bash.
lrwxrwxrwx 1 root root /bin/sh -> bash
I know that shebang line is used to tell shell which interpreter to use for your rest of the script.
If I miss shebang line in perl, give execute permissions and run ./myscript.pl, it doesn't work.
What's actually happening here? If I use ./, When is shebang line actually needed?

The parent shell, where you entered ./myscript.sh, first tried to execve it, which is where the shebang line would take effect if present. When this works, the parent is unaware of the difference between scripts and ELFs because the kernel takes care of it.
The execve failed, so an ancient unix compatibility feature, predating the existence of shebang lines, was activated. It guessed that a file which has execute permission but is not recognized as a valid executable file by the kernel must be a shell script.
Usually the parent shell guesses that the script is written for the same shell (minimal Bourne-like shells run the script with /bin/sh, bash runs it as a bash subprocess), csh does some more complicated guessing based on the first character because it predates shebang too and it needed to coexist with Bourne shell).
You need a shebang line when you know these guesses will be wrong (for example with the shebang is #!/usr/bin/perl), or when you don't trust the guessing to work consistently, or when the script needs to be runnable by a parent process that is not a shell itself.

shebang line is needed in the file and only if it's meant to be run as executable (as opposed to sh file.sh invocation. It is not actually needed by script, it is for the system to know how to find interpreter.
EDIT: Sorry for misreading the question. If the shebang line is missing or not recognized, /bin/sh is used. But I prefer being explicit about the interpreter.
Note, that this behavior is not universal, IIRC, only some exec* family function do that (not to mention different platforms), so that's another reason to be explicit here.

The POSIX (Single UNIX Specification 4) standard is not helpful:
If the first line of a file of shell commands starts with the characters "#!" , the results are unspecified.
So, the standard implies that if you don't have #! then it should run a POSIX shell. But modern shells are not POSIX compliant. The old Korn Shell 88 (ksh88) ran the Bourne shell (close to a POSIX shell) with no #! line, but ksh93 breaks that, and so does Bash. With both ksh93 and Bash, they run their own shell if no #! line is present.
Despite popular opinion, Bash and Korn shells differ. When you write a shell script you can never be sure what shell you will be run from, or even if it will be run from another shell at all (most programming languages can run other programs). The minute you use something outside of Bourne/POSIX syntax you will be scuppered.
Always use a #! line, don't leave it to chance.

Related

How to run a tsch script from a bash shell system?

So I have a few tcsh scripts associated with an expensive software that I have to run them on a bash shell system. Is that even possible? This software needs these scripts frequently and is based on tcsh. Is it possible to run 2 shells at the same time? Or just call tcsh shell at the beginning of the script? or is there any compiler to translate the shell scripts? What are my options? Thank you.
Simply put a proper shebang at the top of the script.
Assuming your tcsh is installed as /bin/tcsh, each tcsh script should have this as its first line:
#!/bin/tcsh -f
(The -f tells the shell not to load your startup scripts such as .login or .tcshrc. Any script shouldn't depend on your user environment, so you don't need to invoke your startup scripts -- and it will make your scripts load faster. Note that -f has a different meaning for Bourne-derived shells; use -f only for csh and tcsh scripts.)
If you can't portably assume where tcsh is installed, an alternative is:
#!/usr/bin/env tcsh
But that doesn't let you use the -f option, and it could have other disadvantages; see this answer for details.
Note that there really isn't such a thing as a "bash shell system". Both bash and tcsh are just programs that you can run. One or the other might happen to be the default interactive shell for newly created user accounts, but that doesn't affect being able to run either of them.

How do i make my own created shell work with .sh files

My teacher gave us this assignment to create our own shell. Our shell is supposed be called rshell and is supposed to work like the regular shell.
I created my own shell using C++. If you type a command like ls in my created shell it gives you a list just like how if you typed ls in the regular shell.
The problem I am facing is how do I get the .sh files or script files to work with my created shell. I noticed when I run a .sh file using my shell it does not run the .sh file through my shell. It runs it through the regular shell. How do I make .sh files run through my shell?
Change the hash-bang line of the scripts to point at your shell. For instance,
#!/usr/local/bin/rshell
Or wherever your shell executable is.
As John already said, change the shebang to point to your shell. The kernel will invoke the command in the shebang with the file itself as an argument. To demonstrate, try a file with a shebang of #!/bin/cat.
#!/bin/cat
hello world
It pretty much behaves the same as if you typed /bin/cat /path/to/file.
The shebang does not have PATH lookup capabilities, so #!yourshell would not work as a shebang. However, you can use env to do the PATH lookup as in #!/usr/bin/env yourshell. (This approach is preferred for commands that are at different paths on different systems, like python.)

How to know what script header to use and why it matters?

I infrequently have to write bash scripts for various unrelated purposes and while I usually have a good idea what commands I want in the script, I often have no idea what header to use or why I'm using one when I do find it. For example(s):
Standard shell script:
#!/bin/bash
Python:
#!/usr/bin/env python
Scripts seem to work fine without headers but if headers are the standard, there's a reason for them and they shouldn't be ignored. If it has an effect, then it's a valuable tool that could be used to accomplish more.
Minimally, I'd like to know what headers to use with MySQL scripts and what the headers do on Standard, Python, and MySQL scripts. Ideally, I'd like a generic list of headers or an understanding of how to create a header based on what program is being used.
How the Kernel Executes Things
Simplified (a bit), there are two ways the kernel in a POSIX system knows how to execute a program. One, if the program is in a binary format the kernel understands (such as ELF), the kernel can execute it "directly" (more detail out of scope). If the program is a text file starting with a shebang, such as
#!/usr/bin/somebinary -arg
or what-have-you, the kernel actually executes the command as if it had been directed to execute:
/usr/bin/somebinary -arg "$0"
where $0 here is the name of the script file you just tried to execute. (So you can immediately tell why so many scripting languages use # as a comment-starter – it means they don't have to treat the shebang as special.)
PATH and the env command
The kernel does not look at the PATH environment variable to determine which executable you're talking about, so if you are distributing a python script to systems that may have multiple versions of python installed, you can't guarantee that there will be a
#!/usr/bin/python
env, however, is POSIX, so you can count on it existing, and it will look up python in PATH. Thus,
#!/usr/bin/env python
will execute the script with the first python found in your PATH.
BASH, SH and Special Meanings for Invocation
Some programs have special semantics for how they're invoked. In particular, on many systems /bin/sh is a symlink to another shell, such as /bin/bash. While bash does not contain a perfectly POSIXLY_STRICT implementation of sh, when it is invoked as /bin/sh it is stricter than it would be if invoked as plain-old-bash.
MySQL and arg limitations
The shebang line can be length limited and technically, it can only support one argument, so mysql is a bit tricky – you can't expect to pass a username and database name to a mysql script.
#!/usr/bin/env mysql
use mydb;
select * from mytbl;
Will fail because the kernel will try mysql "$0". Even if you have your credentials in a .my.cnf file, mysql itself will try to treat "$0" as a database name. Likewise:
#!/usr/bin/mysql -e
use mydb;
select * from mytbl;
will fail because again, "$0" is not a table name (you hope).
There does not seem to be an appropriate syntax for directly executing a mysql script this way. Your best bet is to pipe the sql commands to mysql directly:
mysql < my_sql_commands
http://mywiki.wooledge.org/BashGuide/Practices#Choose_Your_Shell
When the first line of a script starts with #!, that's what's called a "shebang". When that script is run as an executable, the operating system uses that line to determine how to run the script -- that is to say, to find the program with which the script should be executed.
It's incorrect that "scripts work fine without headers" -- if you don't have a shebang line, you can't be invoked using the execve() call, which means that many (most?) programs won't be able to execute your script. Sometimes invocation from a shell will try to use that shell itself in the absence of a shebang, but you can't trust that to be the case.
(There's an exception to that -- if someone starts your script by running sh yourscript or bash yourscript, the shebang line isn't read at all, and the script they chose is used; however, running scripts this way is a bad practice, as the author typically knows better than the user what the correct interpreter is).
In short:
If you want to use modern features, and you want the user to be able to override the shell version in use by putting a different release of bash earlier in their path, use #!/usr/bin/env bash
If you want to use modern features and ensure that you always run with the system shell, use #!/bin/bash
If you're going to write your script to strictly conform with POSIX sh, use #!/bin/sh
There's not a limited list of shebang lines we can give you, since any native executable (non-script program) can be used as a script interpreter, and thus be placed in a shebang. If you created a file called myscript with #!/usr/bin/env yourprogram, gave it executable permissions, and ran ./myscript foo bar, this would result in /usr/bin/env yourprogram myscript foo bar being invoked; yourprogram would be run by /usr/bin/env (after a PATH lookup), and would be responsible for knowing what to do with myscript and its arguments.
For an extremely detailed history of shebang lines and how they work across systems both modern and ancient, see http://www.in-ulm.de/~mascheck/various/shebang/

Why do you need to put #!/bin/bash at the beginning of a script file?

I have made Bash scripts before and they all ran fine without #!/bin/bash at the beginning.
What's the point of putting it in? Would things be any different?
Also, how do you pronounce #? I know that ! is pronounced as "bang."
How is #! pronounced?
It's a convention so the *nix shell knows what kind of interpreter to run.
For example, older flavors of ATT defaulted to sh (the Bourne shell), while older versions of BSD defaulted to csh (the C shell).
Even today (where most systems run bash, the "Bourne Again Shell"), scripts can be in bash, python, perl, ruby, PHP, etc, etc. For example, you might see #!/bin/perl or #!/bin/perl5.
PS:
The exclamation mark (!) is affectionately called "bang". The shell comment symbol (#) is sometimes called "hash".
PPS:
Remember - under *nix, associating a suffix with a file type is merely a convention, not a "rule". An executable can be a binary program, any one of a million script types and other things as well. Hence the need for #!/bin/bash.
To be more precise the shebang #!, when it is the first two bytes of an executable (x mode) file, is interpreted by the execve(2) system call (which execute programs). But POSIX specification for execve don't mention the shebang.
It must be followed by a file path of an interpreter executable (which BTW could even be relative, but most often is absolute).
A nice trick (or perhaps not so nice one) to find an interpreter (e.g. python) in the user's $PATH is to use the env program (always at /usr/bin/env on all Linux) like e.g.
#!/usr/bin/env python
Any ELF executable can be an interpreter. You could even use #!/bin/cat or #!/bin/true if you wanted to! (but that would be often useless)
It's called a shebang. In unix-speak, # is called sharp (like in music) or hash (like hashtags on twitter), and ! is called bang. (You can actually reference your previous shell command with !!, called bang-bang). So when put together, you get haSH-BANG, or shebang.
The part after the #! tells Unix what program to use to run it. If it isn't specified, it will try with bash (or sh, or zsh, or whatever your $SHELL variable is) but if it's there it will use that program. Plus, # is a comment in most languages, so the line gets ignored in the subsequent execution.
Every distribution has a default shell. Bash is the default on the majority of the systems. If you happen to work on a system that has a different default shell, then the scripts might not work as intended if they are written specific for Bash.
Bash has evolved over the years taking code from ksh and sh.
Adding #!/bin/bash as the first line of your script, tells the OS to invoke the specified shell to execute the commands that follow in the script.
#! is often referred to as a "hash-bang", "she-bang" or "sha-bang".
The shebang is a directive to the loader to use the program which is specified after the #! as the interpreter for the file in question when you try to execute it. So, if you try to run a file called foo.sh which has #!/bin/bash at the top, the actual command that runs is /bin/bash foo.sh. This is a flexible way of using different interpreters for different programs. This is something implemented at the system level and the user level API is the shebang convention.
It's also worth knowing that the shebang is a magic number - a human readable one that identifies the file as a script for the given interpreter.
Your point about it "working" even without the shebang is only because the program in question is a shell script written for the same shell as the one you are using. For example, you could very well write a javascript file and then put a #! /usr/bin/js (or something similar) to have a javascript "Shell script".
The operating system takes default shell to run your shell script. so mentioning shell path at the beginning of script, you are asking the OS to use that particular shell. It is also useful for portability.
It is called a shebang. It consists of a number sign and an exclamation point character (#!), followed by the full path to the interpreter such as /bin/bash. All scripts under UNIX and Linux execute using the interpreter specified on a first line.
Bash standards for “Bourne-Again shell” is just one type of many available
shells in Linux.
A shell is a command line interpreter that accepts and runs commands.
Bash is often the default shell in most Linux distributions. This is why bash is
synonymous to shell.
The shell scripts often have almost the same syntaxes, but they also differ sometimes. For example, array index starts at 1 in Zsh instead of 0 in bash. A script
written for Zsh shell won’t work the same in bash if it has arrays.
To avoid unpleasant surprises, you should tell the interpreter that your shell script
is written for bash shell. How do you do that?
simply begin your bash script into #!/bin/bash
Also you will see some other parameters after #!/bin/bash,
for example
#!/bin/bash -v -x
read this to get more idea.
https://unix.stackexchange.com/questions/124272/what-do-the-arguments-v-and-x-mean-to-bash .
It can be useful to someone that uses a different system that does not have that library readily available. If that is not declared and you have some functions in your script that are not supported by that system, you should declare #/bin/bash. I've ran into this problem before at work and now I just include it as a practice.

Linux shell strange situation

Does anyone know why the following script works?
#a-random-junk-string
echo HI
The shell executes the echo command, and outputs HI. I thought that since there is no "!" after the "#", the shell would give an error.
If there is no #! specifying a specific interpreter, the kernel will not intercept and launch it with the specified program.
However, the current shell may still interpret it as a command file, which is what you are seeing take place.
When the shell is asked to run a file with the executable bit turned on then it will examine the file and determine if it begins with a shebang #! if it does then it will execute that command which will get it's program text from the remainder of the file.
If the file does not start with a shebang then the shell will attempt to execute it itself. This is what is happening for you and the shell interprets the first line as a comment.

Resources