ian@hpopd.HP.COM (Ian Watson) (10/11/90)
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 shell script. I've tried this on both HP-UX 7.0 (which works as I expect) and SCO Unix V.3.2 (which doesn't). I can't seem to get SCO's csh to run the script through the Bourne shell. Is this feature of the C shell standard Unix, and am I doing something wrong ? 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 ? Also, on the HP-UX, I notice that $ csh script and $ csh < script run the script in the C shell, but $ csh followed by % script 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 ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ian Watson, HP Pinewood Information Systems Division, England. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Phone : (Intl)+44 344 763015 Unix mail (Internet) : ian@hpopd.HP.COM Unix mail (UUCP) : ...!hplabs!hpopd!ian Openmail : ian watson/pinewood,lab,hpopd Openmail from Unix : ian_watson/pinewood_lab_hpopd@hpopd HPDesk : Ian WATSON/HP1600 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/12/90)
In article <7980005@hpopd.HP.COM> ian@hpopd.HP.COM (Ian Watson) writes: >#!/bin/sh On systems that support this, the kernel takes care of it as indicated under EXEC(2) in the reference manual. >I understand that the C shell sees this ... Normal shells first try to exec() the file, and if that fails due to unknown executable image format then MIGHT peek at the FIRST character to determine whether or not a Bourne shell or C-shell should be used to interpret the file. The C-shell often is set up to decide that an initial '#' character indicates the file is a C-shell script, but of course that is not a reliable test. Other shells simply always use a Bourne shell, which is what I recommend. It is possible that somebody has hacked their shells to try to apply full #!-style decoding in lieu of having support for it in exec(), but that would be pretty awful.
bhoughto@cmdnfs.intel.com (Blair P. Houghton) (10/13/90)
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?"
maart@cs.vu.nl (Maarten Litmaath) (10/13/90)
In article <397@inews.intel.com>, bhoughto@cmdnfs.intel.com (Blair P. Houghton) writes: )... )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. Wrong. If the file `foo' has `#!/bin/sh' as its first line, executing `foo' will result in `/bin/sh foo', i.e. the filename is passed as an _argument_. If the rest of the file were passed as input to the interpreter, e.g. the following example would not work: #!/bin/sh echo 'Give the name:' read name echo "The name is: $name" Issuing the command `sh < foo' would have the same unwanted effects. -- Waiting for this to work: cat /internet/cs.vu.nl/finger/maart
tchrist@convex.COM (Tom Christiansen) (10/13/90)
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 >shell script. On any system I've seen, it's the kernel who recognizes this (often in sys/kern_exec.c) and launches the proper interpreter. I happen to believe that doing anything else than this is undesirable -- currently either csh or sh may end up being called (on a BSD system) if the program doesn't have either the magic number of compiled a.out or an interpreter line, depending on the first character (# or not) of the file. --tom -- "UNIX was never designed to keep people from doing stupid things, because that policy would also keep them from doing clever things." [Doug Gwyn]