am_I_sourced()
{
if [ "${FUNCNAME[1]}" = source ]; then
if [ "$1" = -v ]; then
echo "I am being sourced, this filename is ${BASH_SOURCE[0]} and my caller script/shell name was $0"
fi
return 0
else
if [ "$1" = -v ]; then
echo "I am not being sourced, my script/shell name was $0"
fi
return 1
fi
}
if am_I_sourced -v; then
echo "Do something with sourced script"
else
echo "Do something with executed script"
fi
现在尝试以多种方式执行它:
~/toys/bash $ chmod a+x include2.sh
~/toys/bash $ ./include2.sh
I am not being sourced, my script/shell name was ./include2.sh
Do something with executed script
~/toys/bash $ bash ./include2.sh
I am not being sourced, my script/shell name was ./include2.sh
Do something with executed script
~/toys/bash $ . include2.sh
I am being sourced, this filename is include2.sh and my caller script/shell name was bash
Do something with sourced script
source <(echo $'#!/bin/bash
[ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 29301 is sourced (bash, /dev/fd/63)
bash <(echo $'#!/bin/bash
[ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 16229 is own (/dev/fd/63, /dev/fd/63)
为了可读性,我使用source代替.(因为.是source的别名):
. <(echo $'#!/bin/bash
[ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 29301 is sourced (bash, /dev/fd/63)
注意,当进程保持采购时,进程号不会改变:
echo $$
29301
为什么不使用$_ == $0比较
为了确保多种情况,我开始编写真正的脚本:
#!/bin/bash
# As $_ could be used only once, uncomment one of two following lines
#printf '_="%s", 0="%s" and BASH_SOURCE="%s"\n' "$_" "$0" "$BASH_SOURCE"
[[ "$_" != "$0" ]] && DW_PURPOSE=sourced || DW_PURPOSE=subshell
[ "$0" = "$BASH_SOURCE" ] && BASH_KIND_ENV=own || BASH_KIND_ENV=sourced;
echo "proc: $$[ppid:$PPID] is $BASH_KIND_ENV (DW purpose: $DW_PURPOSE)"
将其复制到名为testscript的文件中:
cat >testscript
chmod +x testscript
现在我们可以测试:
./testscript
proc: 25758[ppid:24890] is own (DW purpose: subshell)
没关系。
. ./testscript
proc: 24890[ppid:24885] is sourced (DW purpose: sourced)
source ./testscript
proc: 24890[ppid:24885] is sourced (DW purpose: sourced)
没关系。
但是,在添加-x标志之前测试脚本:
bash ./testscript
proc: 25776[ppid:24890] is own (DW purpose: sourced)
或者使用预定义的变量:
env PATH=/tmp/bintemp:$PATH ./testscript
proc: 25948[ppid:24890] is own (DW purpose: sourced)
env SOMETHING=PREDEFINED ./testscript
proc: 25972[ppid:24890] is own (DW purpose: sourced)
这已经不管用了。
将注释从第5行移到第6行会给出更易读的答案:
./testscript
_="./testscript", 0="./testscript" and BASH_SOURCE="./testscript"
proc: 26256[ppid:24890] is own
. testscript
_="_filedir", 0="bash" and BASH_SOURCE="testscript"
proc: 24890[ppid:24885] is sourced
source testscript
_="_filedir", 0="bash" and BASH_SOURCE="testscript"
proc: 24890[ppid:24885] is sourced
bash testscript
_="/bin/bash", 0="testscript" and BASH_SOURCE="testscript"
proc: 26317[ppid:24890] is own
env FILE=/dev/null ./testscript
_="/usr/bin/env", 0="./testscript" and BASH_SOURCE="./testscript"
proc: 26336[ppid:24890] is own
# Helper function
is_sourced() {
if [ -n "$ZSH_VERSION" ]; then
case $ZSH_EVAL_CONTEXT in *:file:*) return 0;; esac
else # Add additional POSIX-compatible shell names here, if needed.
case ${0##*/} in dash|-dash|bash|-bash|ksh|-ksh|sh|-sh) return 0;; esac
fi
return 1 # NOT sourced.
}
# Sample call.
is_sourced && sourced=1 || sourced=0
编者注:这个答案的解决方案工作稳健,但是bash-only。它可以精简为 (return 2>/dev/null)。< /一口> < / p >
博士TL;
尝试执行return语句。如果脚本没有来源,则会引发错误。您可以捕获该错误并按照需要进行操作。
把它放在一个文件中,并调用它,比如test.sh:
#!/usr/bin/env sh
# Try to execute a `return` statement,
# but do it in a sub-shell and catch the results.
# If this script isn't sourced, that will raise an error.
$(return >/dev/null 2>&1)
# What exit code did that give?
if [ "$?" -eq "0" ]
then
echo "This script is sourced."
else
echo "This script is not sourced."
fi
直接执行:
shell-prompt> sh test.sh
output: This script is not sourced.
来源:
shell-prompt> source test.sh
output: This script is sourced.
#!/bin/bash
echo "First Parameter: $0"
echo
if [[ "$0" == "bash" || "$0" == "-bash" ]] ; then
echo "The script was sourced."
else
echo "The script WAS NOT sourced."
fi
或
#!/bin/bash
echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
echo "The script was sourced."
elif [[ "$0" == "-bash" ]] ; then
echo "The script was sourced via SSH session."
else
echo "The script WAS NOT sourced."
fi
#!/bin/bash
# Function definitions (API) and shell variables (constants) go here
# (This is what might be interesting for other shells, too.)
# this main() function is only meant to be meaningful for bash
main()
{
# The script's execution part goes here
}
BASH_SOURCE=".$0" # cannot be changed in bash
test ".$0" != ".$BASH_SOURCE" || main "$@"
# NOTE: This script may be used as a standalone executable, or callable library.
# To source this script, add the following *prior* to including it:
# export ENTRY_POINT="$0"
main()
{
echo "Running in direct executable context!"
}
if [ -z "${ENTRY_POINT}" ]; then main "$@"; fi
# A. Place this line OUTSIDE all functions:
(return 0 2>/dev/null) && script_is_being_executed="false" || script_is_being_executed="true"
# B. Place these lines anywhere
if [ "$script_is_being_executed" == "true" ]; then
echo " This script is being EXECUTED."
run="true"
else
echo " This script is being SOURCED."
fi
if [ "${FUNCNAME[-1]}" == "main" ]; then
echo " This script is being EXECUTED."
run="true"
elif [ "${FUNCNAME[-1]}" == "source" ]; then
echo " This script is being SOURCED."
else
echo " ERROR: THIS TECHNIQUE IS BROKEN"
fi
replace_shell(){
if [ -n "$ZSH_EVAL_CONTEXT" ]; then
case $ZSH_EVAL_CONTEXT in *:file*) echo "Zsh is sourced";; esac
else
case ${0##*/} in sh|dash|bash) echo "Bash is sourced";; esac
fi
}