Choose bash or zsh for FileWave macOS Scripts
Description
Starting with macOS 10.15, Apple uses zsh as the default login and interactive shell. That change does not override the interpreter named by a script's shebang.
Apple reference: Use zsh as the default shell on Mac
FileWave script behavior
FileWave adds #!/bin/zsh to a new macOS shell script in the Fileset editor. Existing scripts keep their current shebang, so a script that explicitly starts with #!/bin/bash continues to request bash.
Choose the interpreter the script actually requires, then test it on the same macOS versions and execution context used by the FileWave Client. Do not change a working bash script to zsh without checking syntax and behavior.
Login-shell and script-shell settings are separate. Changing a user's default shell affects interactive and login sessions. An explicit shebang controls a directly executed script.
For FileWave script types, extensions, runtime ownership, and logging behavior, see Scripting Languages and File Extensions in FileWave.
Considerations
Specifying the shell
The first line of a script should indicate which shell is used when a script runs.
For example, for bash this could typically be either of the following (this is known as the 'shebang'):
#!/bin/bash
#!/usr/bin/env bash
A shebang makes the interpreter choice explicit and repeatable. Always include one at the beginning of a Fileset script instead of relying on fallback shell behavior. Use #!/usr/bin/env bash only when the managed device's environment is expected to resolve the intended bash binary.
Bash vs zsh
Bash and zsh are very similar, but there are some differences that may interfere with scripts that were written for bash but are then run as zsh. Scripts should therefore be analyzed for behavior if the shell type of the script is changed.
Examples
Arrays
The first item of an array differs when being referenced:
- bash reference of the first item in an array: index 0
- zsh reference of the first item in an array: index 1
There is also a difference in deleting items from an array. The following produces the same output from the same original array, but note differences on the item being indexed and the method of removal:
bash arrays
#!/bin/bash
myarray=("one" "two" "three")
echo ${myarray[@]}
echo "First item in array: "${myarray[0]}
echo "Remove first item in array, item 0..."
unset myarray[0]
echo ${myarray[@]}
exit 0
# Script output:
one two three
First item in array: one
Remove first item in array, item 0...
two three
zsh arrays
#!/bin/zsh
myarray=("one" "two" "three")
echo ${myarray[@]}
echo "First item in array: "${myarray[1]}
echo "Remove first item in array, item 1..."
myarray[1]=()
echo ${myarray[@]}
exit 0
# Script output:
one two three
First item in array: one
Remove first item in array, item 1...
two three
Variable Expansion
Word splitting on variable expansion differs between bash and zsh. For example, bash will print the following, one line per word, whilst zsh will print the whole variable as one line. Note also, that bash, by default, will not expand aliases when the shell is not interactive, unlike zsh.
bash variable expansion
#!/bin/bash
# Expand aliases
shopt -s expand_aliases
alias printvar="printf '%s\n'"
myvar='one two'
printvar $myvar
exit 0
# Script output:
one
two
zsh variable expansion
#!/bin/zsh
alias printvar="printf '%s\n'"
myvar='one two'
printvar $myvar
exit 0
# Script output
one two
zsh does have the ability to set an option to change this behavior, but consider converting to an array instead.
zsh is broadly compatible with Bourne-style shells, but it is not a drop-in replacement for every bash script. Test array handling, word splitting, aliases, conditionals, and any external commands before deploying a changed interpreter broadly.
No comments to display
No comments to display