|
#!/bin/bash |
|
|
|
# test-shell-default-variables.sh |
|
|
|
# Usage examples (you might want to `sudo apt install zsh ksh`): |
|
# |
|
# ./test-shell-default-variables.sh dash bash |
|
# ./test-shell-default-variables.sh dash bash zsh ksh |
|
# ./test-shell-default-variables.sh dash bash zsh ksh | less -R |
|
|
|
# `-R` in `less -R` to have less pass escape sequences directly to the terminal |
|
# so we have colors. |
|
|
|
|
|
# The "when named `sh`" tests are commented because for every shell I tested |
|
# (dash, bash, zsh and ksh), the output was the same as that of dash. |
|
|
|
# The `test_expression` function also work with expansion changes. You can try |
|
# lines like `test_expression '{BASH_SOURCE:-$0}'`. |
|
|
|
echolor() { |
|
echo -e "\e[1;36m$@\e[0m" |
|
} |
|
|
|
tell_file() { |
|
echo File \`"$1"\` is: |
|
echo \`\`\` |
|
cat "$1" |
|
echo \`\`\` |
|
echo |
|
} |
|
|
|
SHELL_ARRAY=("$@") |
|
|
|
test_command() { |
|
for shell in "${SHELL_ARRAY[@]}" |
|
do |
|
prepare "$shell" |
|
cmd="$(eval echo $1)" |
|
# echo "cmd: $cmd" |
|
printf '%-4s: ' "$shell" |
|
{ env -i $cmd 2>&1 1>&3 | sed 's/^/[err]/'; } 3>&1 |
|
teardown |
|
done |
|
echo |
|
} |
|
|
|
prepare () { |
|
shell="$1" |
|
PATH="$PWD/$shell/sh:$PATH" |
|
} |
|
|
|
teardown() { |
|
PATH="${PATH#*:}" |
|
} |
|
|
|
|
|
### |
|
### prepare |
|
### |
|
for shell in "${SHELL_ARRAY[@]}" |
|
do |
|
mkdir "$shell" |
|
ln -sT "/bin/$shell" "$shell/sh" |
|
done |
|
|
|
echo > printer.sh |
|
echo '. ./printer.sh' > sourcer.sh |
|
rm linked.sh &>/dev/null; ln -sT "printer.sh" "linked.sh" |
|
|
|
tell_file sourcer.sh |
|
|
|
### |
|
### run |
|
### |
|
test_expression() { |
|
local expr="$1" |
|
|
|
# prepare |
|
echo "echo $expr" > printer.sh |
|
tell_file printer.sh |
|
|
|
# run |
|
cmd='$shell ./printer.sh' |
|
echolor "\`$cmd\` (simple invocation) ($expr):" |
|
test_command "$cmd" |
|
|
|
# cmd='sh ./printer.sh' |
|
# echolor "\`$cmd\` (when executable name is \`sh\`) ($expr):" |
|
# test_command "$cmd" |
|
|
|
cmd='$shell ./sourcer.sh' |
|
echolor "\`$cmd\` (via sourcing) ($expr):" |
|
test_command "$cmd" |
|
|
|
# cmd='sh ./sourcer.sh' |
|
# echolor "\`$cmd\` (via sourcing, when name is \`sh\`) ($expr):" |
|
# test_command "$cmd" |
|
|
|
cmd='$shell ./linked.sh' |
|
echolor "\`$cmd\` (via symlink) ($expr):" |
|
test_command "$cmd" |
|
|
|
# cmd='sh ./linked.sh' |
|
# echolor "\`$cmd\` (via symlink, when name is \`sh\`) ($expr):" |
|
# test_command "$cmd" |
|
|
|
echolor "------------------------------------------" |
|
echo |
|
} |
|
|
|
test_expression '$BASH_SOURCE' |
|
test_expression '$0' |
|
test_expression '$(/bin/true x y; true a b c; echo $_)' # Rq: true is a builtin |
|
test_expression '$_' |
|
|
|
### |
|
### teardown |
|
### |
|
for shell in "${SHELL_ARRAY[@]}" |
|
do |
|
rm "$shell/sh" |
|
rm -d "$shell" |
|
done |
|
|
|
rm sourcer.sh |
|
rm linked.sh |
|
rm printer.sh |
|
|
|
true ' |
|
# Sample output: |
|
|
|
`$ ./test-shell-default-variables.sh {da,ba,z,k}sh` |
|
|
|
`````` |
|
File `sourcer.sh` is: |
|
``` |
|
. ./printer.sh |
|
``` |
|
|
|
File `printer.sh` is: |
|
``` |
|
echo $BASH_SOURCE |
|
``` |
|
|
|
`$shell ./printer.sh` (simple invocation) ($BASH_SOURCE): |
|
dash: |
|
bash: ./printer.sh |
|
zsh : |
|
ksh : |
|
|
|
`$shell ./sourcer.sh` (via sourcing) ($BASH_SOURCE): |
|
dash: |
|
bash: ./printer.sh |
|
zsh : |
|
ksh : |
|
|
|
`$shell ./linked.sh` (via symlink) ($BASH_SOURCE): |
|
dash: |
|
bash: ./linked.sh |
|
zsh : |
|
ksh : |
|
|
|
------------------------------------------ |
|
|
|
File `printer.sh` is: |
|
``` |
|
echo $0 |
|
``` |
|
|
|
`$shell ./printer.sh` (simple invocation) ($0): |
|
dash: ./printer.sh |
|
bash: ./printer.sh |
|
zsh : ./printer.sh |
|
ksh : ./printer.sh |
|
|
|
`$shell ./sourcer.sh` (via sourcing) ($0): |
|
dash: ./sourcer.sh |
|
bash: ./sourcer.sh |
|
zsh : ./printer.sh |
|
ksh : ./sourcer.sh |
|
|
|
`$shell ./linked.sh` (via symlink) ($0): |
|
dash: ./linked.sh |
|
bash: ./linked.sh |
|
zsh : ./linked.sh |
|
ksh : ./linked.sh |
|
|
|
------------------------------------------ |
|
|
|
File `printer.sh` is: |
|
``` |
|
echo $(/bin/true x y; true a b c; echo $_) |
|
``` |
|
|
|
`$shell ./printer.sh` (simple invocation) ($(/bin/true x y; true a b c; echo $_)): |
|
dash: |
|
bash: c |
|
zsh : c |
|
ksh : |
|
|
|
`$shell ./sourcer.sh` (via sourcing) ($(/bin/true x y; true a b c; echo $_)): |
|
dash: |
|
bash: c |
|
zsh : c |
|
ksh : |
|
|
|
`$shell ./linked.sh` (via symlink) ($(/bin/true x y; true a b c; echo $_)): |
|
dash: |
|
bash: c |
|
zsh : c |
|
ksh : |
|
|
|
------------------------------------------ |
|
|
|
File `printer.sh` is: |
|
``` |
|
echo $_ |
|
``` |
|
|
|
`$shell ./printer.sh` (simple invocation) ($_): |
|
dash: |
|
bash: bash |
|
zsh : |
|
ksh : |
|
|
|
`$shell ./sourcer.sh` (via sourcing) ($_): |
|
dash: |
|
bash: bash |
|
zsh : ./printer.sh |
|
ksh : |
|
|
|
`$shell ./linked.sh` (via symlink) ($_): |
|
dash: |
|
bash: bash |
|
zsh : |
|
ksh : |
|
|
|
------------------------------------------ |
|
`````` |
|
' |
|
|
|
true ' |
|
# What did we learn ? |
|
|
|
### `$BASH_SOURCE` |
|
|
|
* `$BASH_SOURCE` works in bash and only in bash. |
|
* The only difference with `$0` is when the current file was sourced by |
|
another file. In that case, `$BASH_PROFILE` contains the name of the |
|
sourced file, rather than that of the souring file. |
|
|
|
### `$0` |
|
|
|
* In zsh, `$0` has the same value as `$BASH_SOURCE` in bash. |
|
|
|
### `$_` |
|
|
|
* `$_` is left untouched by dash and ksh. |
|
* In bash and zsh, `$_` decays to the last argument of the last call. |
|
* bash initializes `$_` to "bash". |
|
* zsh leaves `$_` untouched. |
|
(when sourcing, it`s just the result of the "last argument" rule). |
|
|
|
### Symlinks |
|
|
|
* When a script is called through a symlink, no variable contains any |
|
reference to the destination of the link, only its name. |
|
|
|
### ksh |
|
|
|
* Regarding those tests, ksh behaves like `dash`. |
|
' |