How to start a script with clean environment?

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, -i and /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:

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

The 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.

Testing the 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.

Example output:

declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"