I tried the following but it doesn't seem to work:
$ cat script.sh #!/bin/env -i /bin/sh /bin/env $ script.sh /bin/env: invalid option -- ' ' Try `/bin/env --help' for more information.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
The reason this does not work is because it sees
-i /bin/sh as a single argument to
env. Usually this would be 2 arguments,
/bin/sh. This is just a limitation of the shebang. No way around it.
However you can still perform this task, just a different way.
If you want this task to be performed by the script itself, and not have to do something like
env -i script.sh, you can have the script re-exec itself.
#!/bin/sh [ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
This will cause the script to re-exec itself if the
CLEANED environment variable isn't set. Then on re-exec, it sets the variable to make sure that it doesn't go into a loop.
Run your script with
env -i script.sh
And the script as usual:
#!/bin/sh # ... your code here
If you mean to run with a clean environment without explicitly say that when you run. Eduardo Ivanec gives some ideas in this answer, you can recursively call your script with
exec when the environment is not clean (e.g. $HOME is defined):
[ "$HOME" != "" ] && exec -c $0
With bash, you can do it like this:
#!/usr/bin/bash set -e set -u [ -v HOME ] && exec -c "$0" "$@" # continue with the rest of the script # e.g. print the cleaned environment: export
set -e and
set -u commands are not strictly necessary, but I include them to demonstrate that this approach doesn't rely on accessing unset variables (as e.g.
[ "$HOME" != "" ] would) and is compatible with a
set -e setting.
HOME variable should be safe because bash executes scripts in non-interactive mode, i.e. configuration files like
~/.bashrc (where environment variables may be set) are not sourced during startup.
declare -x OLDPWD declare -x PWD="/home/juser" declare -x SHLVL="1"
$ cat script.sh
#!/bin/env -i /bin/sh
Sadly it won't work that way — Linux does consider
-i /bin/sh as one argument to be passed to
env (see Shebang).
The Linux 2-argument shebang limitation (interpeter + single argument) is noted in most of the answers, but to say this cannot be done is incorrect — you just need to change to an interpreter that can do something useful with a single argument:
#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV; # your sh script here
What this does is invoke
perl with a one-liner script (
-e) that clears
%ENV (cheaper than
env -i) and invokes
exec /bin/sh, correctly quoting the arguments. Further
perl logic can be added, if required (though not much on Linux since you're limited to
BINPRM_BUF_SIZE characters, which is likely 128)
Sadly, this is Linux specific, it will not work on a system which allows multiple shebang arguments :-/
perl processes this string as a single argument, so it's not quoted above as you would ordinarily do with
perl -e ... from the command line (if you were to add quotes these are preserved, perl sees only a literal string, with warnings on it will complain about a useless constant).
Also note there's a slight change in behaviour when used this way,
@ARGV normally contains only the arguments, and
$0 contains the script, but with this shebang
$ARGV is the name of the script (and
-e) which makes it a little easier.
You can also solve this with an interpreter that "reprocesses" its command line (without an extra
-c argument) the ancient AT&T
#!/bin/ksh /usr/bin/env -i /bin/sh
ksh isn't as common nowadays ;-)
bash has a similar feature with
--wordexp, but it's "undocumented" in the versions where it works, and not enabled at compile time in the versions where it is documented :-/ It also can't be used for this since it needs two arguments...)
Also, effectively a variation on @Patrick and @maxschlepzig's answers:
#!/bin/bash [ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@" # your script here
Rather than use a new variable this uses the special "
_" variable, if it's not set to exactly "bash" then replace the script with
-a to make
ARGV (and hence
$_) just "bash", and using
-c to clear the environment.
Alternatively, if it is acceptable to clean the environment at at the start of the script (bash only):
#!/bin/sh unset $(compgen -e) # your script here
compgen (completion helper) to list the names of all the exported environment variables, and
unsets them in one go.
See also Multiple arguments in shebang for more details on the general problem of shebang behaviour.