It depends.
You can put the function in a subshell. (See also Do parentheses really put the command in a subshell?) What happens in a subshell stays in a subshell. Changes that the function makes to variables, the current directory, to redirections, to traps, and so on, do not affect the calling code. The subshell inherits all these properties from its parent but there is no transfer in the other direction. exit
in a subshell only exits the subshell, not the calling process. You can put a piece of code in a subshell by wrapping it in parentheses (line breaks and even whitespace before and after the parentheses are optional):
(
set -e # to exit the subshell as soon as an error happens
cd -- "$1"
do stuff # in $1
)
do more stuff # in whatever directory was current before the '('
If you want to run the whole function in a subshell, you can use parentheses instead of braces to wrap the function's code.
doStuffAt () (
set -e
cd -- "$1"
# do stuff
)
With the Korn-style function definition syntax, you need:
function doStuffAt { (
set -e
cd -- "$1"
# do stuff
) }
The downside of a subshell is that nothing escapes it. If you need to change the current directory but then update some variables, you can't do that with a subshell. There are only two easy ways to retrieve information from a subshell. Like any other command, a subshell has an exit status, but this is an integer between 0 and 255 so it doesn't convey much information. You can use a command substitution to produce some output: a command substitution is a subshell whose standard output (minus trailing newlines) is collected into a string. This lets you output one string.
data=$(
set -e
cd -- "$1"
do stuff # in $1
)
# Now you're still in the original directory, and you have some data in $data
You can save the current directory into a variable, and restore it later.
set -e
old_cwd="$PWD"
cd -- "$1"
…
cd "$old_cwd"
However this is not very reliable. If the code exits between the two cd
commands, it'll be in the wrong directory. If the old directory is moved in the meantime, the second cd
will not return to the right place. It's possible to be in a directory that you have no permission to change into (because the script has less privileges than its caller), and in this case the second cd
will fail. So you should not do this unless you're in a controlled environment where this can't happen (for example, to cd
into and out of a temporary directory created by your script).
If you need to both change directory temporarily and affect the shell environment in some way (such as setting variables), you need to carefully split your scripts into parts that affect the shell environment and parts that change the current directory. The shell inherits limitations of early unix systems which didn't have a way to return to the previous directory. Modern unix systems do (you can “save” the current directory's file descriptor, and return to it with fchdir()
in an exception handler), but there's no shell interface to this functionality.
cd -
at the end of the function to switch back to the cached$OLDPWD
? You don't need to explicitly save it yourself – steeldriver Oct 02 '20 at 17:23cd -
is a good idea, but if the script was sourced and terminated beforecd -
, the shell would be left in the path that was provided as an argument to the function. – Quasímodo Oct 02 '20 at 17:30