Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

What is the most proper way to distribute shell scripts, if behaviours of shells can be modified by set and thus are unpredictable?

For example, rm *.txt wouldn't be executed as expected on the environments in which set -f has been run. How should I make sure that rm *.txt removes all text files in a current directory in any environments?

How should I make that sure that shell scripts will run as expected before distributing them in general?

share|improve this question
    
shell_state=$(set +o) ... script ... eval "$shell_state" –  mikeserv Jul 25 at 22:58
    
You could run those commands at the top of the script itself, or modify the #! to specify what shell options you want. –  HalosGhost Jul 25 at 22:58

1 Answer 1

up vote 5 down vote accepted

Shell scripts are normally treated as if they were the same as any other kind of executable file, such as binaries, Python scripts, Perl scripts, or any other kind of script. They have a shebang at the top that directs the kernel to execute them through the shell. They are expected to be invoked the same way as any other command.

As such, a new shell is started every time the script is invoked, and any settings such as set -f present in the invoking shell or in any other shell instance in the system are irrelevant.

Of course it's possible for users to source your script instead of running it, for instance like this:

. /path/to/your/script

or to execute it in a shell that has non-default settings like this:

sh -f /path/to/your/script

but those are not considered normal ways or invoking your script, and users who do that should expect whatever they get as a result.

Note that there are some scripts that are intended to be sourced, not executed, because their purpose is to to things such as changing the cwd or setting environment variables that must be reflected in the environment of the sourcing shell, but these are in the minority and it's usually done as part of an agreed protocol. These files can be considered more like "plugins" to whatever system they expect to be sourced by, not so much as independent scripts. For example, files in /etc/rc*.d with names that end in .sh are sourced by the startup script subsystem, not executed, and it is documented that this is what will happen if you place a file with such a name in /etc/rc*.d and when it's done it's done on purpose. The convention of naming files intended to be sourced instead of executed in this way is followed elsewhere too, but not universally.

It's true that files intended to be sourced in this way have to take care of what settings might be present in their caller's environment that might affect the behaviour of the shell, but then the agreed protocol should ideally promise a predictable execution environment.

share|improve this answer
1  
zsh has a feature that allows to restore the options to a know set in a local context (emulate -L zsh) which is used extensively in all the extensions shipped with zsh and written as zsh code. See how the bash completion system fails miserably if you set some options like failglob. –  Stéphane Chazelas Jul 26 at 7:57
    
Some shells read your customisation file even when invoked to interpret scripts. That's why you generally use #! /bin/csh -f instead of #! /bin/csh for instance. –  Stéphane Chazelas Jul 26 at 7:59
    
@StéphaneChazelas Haha, yes indeed. Of course that's part of why using csh is a bad idea, right? :-) But I guess zsh has that too, in the form of zshenv. Careful what you put in zshenv for that reason! –  Celada Jul 26 at 8:15
    
@StéphaneChazelas by the way, it's not the first time you teach me something I didn't know (emulate -L in this case) by commenting on one of my answers, and I appreciate it. –  Celada Jul 26 at 8:19
    
Well, ~/.zshenv (where you want to force settings (generally env vars) for all the zsh's (interactive or not) invoked under your name, and generally not used except to work around some other non-zsh problem) is separate from the ~/.zshrc (the interactive customisation shell), so it's, a feature, not a bug. (you can use zsh -f) A bug is when some non-interactive bash shells read your ~/.bashrc (like over ssh and you have to add code to guard against that), or some interactive bash (the login ones) don't read it (and again, you have to add code in your ~/.bash_profile to work around it). –  Stéphane Chazelas Jul 26 at 8:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.