[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: bash scripts and files



michael wrote:
On Wed, 2008-01-09 at 13:26 +0100, Dan H wrote:
On Wed, 09 Jan 2008 12:03:07 +0000
michael <cs@networkingnewsletter.org.uk> wrote:

.bashrc and .bash_profile are different. They are only reasonably
invoked by a bash shell, so it is safe to assume they are written
using bash syntax. They are, after all, configuration files for
bash, so what other language would they be written in?
"reasonably"?!
and where is it stated they are different?
surely they should have the !# at the start too
it's this implicitness that upsets me!
They aren't even executable, so why should they have hash-bang?

aha, now that's a very good point! and perhaps the clearest reason:

scripts are executable and require hash-bang (strictly they don't have
to have that but it's useful to ensure they will run if they contain
shell specifics)

files associated with the innovation of a shell (such
as .bashrc, .cshrc, .bash_profile) are not shells and are not executable
and thus do not require hash-bang

M



This is just the tip of the iceberg, that is to say, the subject is a bit complex, requiring some knowledge of system calls, and history. So this will be a bit long.

UNIX/Linux systems use the fork/exec system calls to handle execution of a program (binary executable). A shell will fork a copy of itself, the copy gets a new PID but is otherwise the same as the parent. The copy (child) then uses exec to overlay itself with the new program code.

But, if the program code is a shell script, the exec will return an error, which the shell will detect. The child shell will then try to read the file as text, treating it as a shell script.

Two things to note in the above: there is no way for what is found in the file and executed in the child, to pollute the parent; and the shell simply assumes the syntax is correct. The script may be as simple as one line, invoking some other command (awk, sed, chmod) with arguments (this is how non-shell scripts were usually handled before hash/bang was invented).

Start up files need to pollute the shell, so they must be sourced. This happens automatically for the start up files the shell knows about, and can be done manually by the user, using the 'dot' (.) or 'source' command, depending on the shell in use.

In the case of sourcing, just as for the case with the failed exec, above, the shell assumes the file format is its own. And, sourced files do *not* need to be made executable. Technically, scripts don't either, you can run them as 'shell script' without doing a chmod.

Now, the history. This rounds out the picture, but is not really necessary for understanding startup scripts.

The original UNIX shell was a loner, there were no other shells, so just reading the file and running the commands was enough. But then came the C shell and it had different syntax. So, the C shell had an extra bit added to it. Reading the first line, if it has a single character and that character is a colon, then the file is not a C shell script, exec a "standard" shell to run it. Otherwise, treat it as a C shell script.

And this worked fine, for a time. But then there were awk and sed, then Perl, Python, and so on. And an easier way was needed to make scripts with these languages work. The standard, with awk and sed, started out to be writing a file with the script, and running awk or sed with an option and script file name, similar to using 'shell script'. But that wasn't good enough, too much typing.

So the exec system call was modified to deal with scripts directly. It will read the first two characters of the executable file and if they are hash/bang, it will use the rest of the line to find the actual file to exec, passing that program the name of the script with any arguments.

--
Bob McGowan

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


Reply to: