Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!olivea!orc!inews!cmdnfs!bhoughto From: bhoughto@cmdnfs.intel.com (Blair P. Houghton) Newsgroups: comp.unix.questions Subject: Re: How does #!/bin/sh work ? Why does it sometimes not ? Message-ID: <397@inews.intel.com> Date: 12 Oct 90 17:07:33 GMT References: <7980005@hpopd.HP.COM> Sender: news@inews.intel.com Organization: Intel Corp, Chandler, AZ Lines: 111 In article <7980005@hpopd.HP.COM> ian@hpopd.HP.COM (Ian Watson) writes: >I've seen loads of shell scripts start with >#!/bin/sh >as the first line. > >I understand that the C shell sees this and knows to execute it as a Bourne Not the C shell. The kernel. When you type the script name, the shell first checks to see if it's a builtin command (like 'cd'), if not, it checks in the directories in $path and execs the first matching filename. It uses the execve(2) call. execve(2) opens the file and sees '#!' as the first two bytes. The first two bytes of an executable are the "magic number." They tell execve(2) what type of executable the file contains (do 'man magic' to see examples; these are used by the file(1) command to see what sort of file you've given it, and may not match exactly with execve(2)'s interpretation). When execve(2) sees '#!' (hex 2321) it interprets the rest of the line as the pathname to an interpreter, and its arguments; it opens _that_ file as an executable, and pipes it the balance of the first file as input. Other things you can do with it are #! nroff -man #! cat #! more Basically, any program that reads stdin for input can be run this way. (Be careful, though, some commands _seem_ to read stdin when they've really opened /dev/tty and are reading your typing raw -- passwd(1) does this). >Why can't I find this feature mentioned in TFM for either HP-UX or SCO Unix ? >Am I just not looking hard enough / in the right place ? Look in execve(2), and in the deeper part of csh(1). sh(1) doesn't say a word (at least under Ultrix), primarily because it does not care what the first line of the file looks like. It passes the script to execve(2) and if execve(2) sees the '#!' it forks a subshell which just gets the file's contents. Csh(1) _will_, however, _after_ giving execve(2) a shot, fork a sh(1) iff the first line of the file is _not_ a comment. I.e., if you do not put a comment or a '#!' as the first line, the script defaults to being a sh-script. >Also, on the HP-UX, I notice that > >$ csh script What you've done here is executed 'csh' to open 'script' and read its contents as input (to source it, albeit in a subshell of the one you're typing into); what you have not done is that you have not executed 'script'. >and >$ csh < script Here you've done the same thing, except the script comes via standard-input rather than another file descriptor that the sub-shell would open (standard-input, -output, and -error are open by default). >run the script in the C shell, but >$ csh Now you've just started a subshell. >followed by >% script Here you've executed the script itself. Csh will go through the routine outlined here: csh recognizes it's not builtin csh builds the pathname by looking through $path members csh fork(2)-and-execve(2)'s the script execve(2) opens the file and looks for the 'magic number' if the magic number is '#!', execve runs the rest of the line as a command and pipes it the rest of the file as standard input and then exits else if the magic number denotes a binary-executable, execve runs the binary and then exits else execve returns (normally it doesn't, it just exits, which is why the fork(2) is used, also) with a status in errno(2) that says "it's not my job, man" csh then opens the file: if the first line is a comment csh reads the rest of the file as commands then exits else csh fork(2)-and-execve(2)'s /bin/sh and pipes it the rest of the file as standard input >does what I want (runs script through Bourne shell). Can anyone explain under >what circumstances the #!/bin/sh line is or is not honoured by the C shell ? To the C shell, that line is a comment; to execve(2), it's the word of god. --Blair "Where's my mitre?"