Originally, we only had one shell on unix. When ran a command, the shell would attempt to invoke one of the exec() system calls on it. It the command was an executable, the exec would succeed and the command would run. If the exec() failed, the shell would not give up, instead it would try to interpret the command file as if it were a shell script. This works fine as long as there is only one shell on the system. But what if you are using one shell as your interactive and want to run a script written in another shell's language?
This is where the #! trick comes in. The idea of using # to represent a comment originated with csh and was quickly added to the bourne shell. Now all shells know to ignore stuff after a #. So we can add a leading line something like "#! /usr/bin/ksh". To the shell this line is just a comment. But if the kernel tries to execute a file with this line, it will exec the specified interpreter and pass the script to it. So shell scripts become executable pretty much like real executables are. Now when a shell tries to exec a shell script, it succeeds.
What if you leave off the #! line? Well, the kernel exec will fail. Your average shell will then try to run the script itself. A few shells will try to inspect the script to try to guess the language. This is not good. You may be running ksh as your interactive shell and writing ksh scripts. If you later switch to bash as an interactive shell, some of your scripts may continue to run while others may fail. Also the line is a comment that provides an important clue to a programmer who looks at the script to understand it. Knowing which language the author is attempting to use is a big help.
While I have used the term "shell", actually this technique can be used with many programs that are not shells. Here is a "script" to display a multiline message:
This will display that "#! /usr/bin/cat" line, but other than that, it works fairly well.
Passing an Argument
You can pass a single argument like this:
#! /usr/local/bin/perl -w
But, in general, you are limited to one argument. On most systems, a line like: "#! /some/interpreter -a -b" will result in "-a -b" being passed as a single argument. However, the single argument is not limited to starting with a hyphen. We can improve on our message script:
Example
Let's put all of this together with an example. Here is a perl script that I will call perlargs:
The -w asks perl issue warning messages. The script simply displays its arguments, then runs the ps command. When I run it, I get:
Notice that the perl process was called with 5 arguments. The 2nd argument is the name of the script. It is up to the perl process to to present the final 3 arguments as the argument list seen by the script. Also realize the kernel started the perl process. After that, it is up to perl to open the script and read it and execute each line. This is why scripts need to be readable. You cannot execute a non-readable script.
Conclusion
This should be enough information to understand what is happening with those #! lines. In the following posts, I will add details on various aspects of the process.
These 4 Users Gave Thanks to Perderabo For This Post:
Hi,
I have a developer that is trying to start a script with sh "scriptname". In the script, he is specifying #!/usr/bin/ksh as the command interpreter. For some reason sh is ignoring the #!/usr/bin/ksh. We are running Solaris 8. Does anyone have any ideas what could be causing this? Here... (3 Replies)
I am using IBM AIX unix version 4.3.3.0.
In a directory there are many files with different patterns.
When I am trying to execute the command, ls -l with the file pattern, which have fewer files it gives the desired result. However when I am trying to execute the same command for file pattern,... (2 Replies)
Hi all,
below is the problem details:
ora10g@CNORACLE1>which ld
/usr/ucb/ld
ora10g@CNORACLE1>cd /usr/ccs/bin
ora10g@CNORACLE1>ln -s /usr/ucb/ld ld
ln: cannot create ld: File exists
ora10g@CNORACLE1>
how to link it to /usr/ccs/bin? (6 Replies)
Usually we use !/usr/bin/ksh at the start of the script.But if I am having this stuff in the scripts and calling one script from other its not working.What may be the reason behind it ?
xyz.ksh
#!/usr/bin/ksh
echo "Hi"
abc.ksh
#!/usr/bin/ksh
echo "I am fine"
ksh xyz.ksh
Its... (4 Replies)
Hi,
I am getting the below error message When i am trying to delete the files from the directory.Could you please guide me?
rm *.aud
ksh: /usr/bin/rm: 0403-027 The parameter list is too long.
and
find /oracle/admin/testP/adump/*.aud -mtime +5 -exec rm {} \;
ksh: /usr/bin/find:... (3 Replies)
Q1. I understand that /usr/local/bin means I can install/uninstall stuff in here and have any chance of messing up my original system files or effecting any other users. I created this directory myself.
But what about the directory I didn't create, namely /Users/m/bin? How is that directory... (1 Reply)
I saw one script using the first line as below
/usr/bin/ksh -E
I have used -x for debug but couldn't find what is this -E option for ?
Pls let me know what is this -E used for
Thanks
RL (1 Reply)
I'm not sure if this is the default behavior for the ld command, but it does not seem to be looking in /usr/local/lib for shared libraries.
I was trying to compile the latest version of Kanatest from svn. The autorgen.sh script seems to exit without too much trouble:
$ ./autogen.sh
checking... (2 Replies)