如何在脚本本身中确定Bash脚本文件的名称?
就像我的脚本在文件中一样runme.sh
,那么我怎么能让它显示"你正在运行runme.sh"的消息而没有硬编码?
me=`basename "$0"`
通过符号链接阅读,通常不是你想要的(你通常不想以这种方式混淆用户),试试:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO,这会产生令人困惑的输出."我跑了foo.sh,但它说我正在运行bar.sh!?一定是个bug!" 此外,具有不同名称的符号链接的目的之一是根据其所称的名称提供不同的功能(在某些平台上考虑gzip和gunzip).
# ------------- SCRIPT ------------- #
#!/bin/bash
echo
echo "# arguments called with ----> ${@} "
echo "# \$1 ----------------------> $1 "
echo "# \$2 ----------------------> $2 "
echo "# path to me ---------------> ${0} "
echo "# parent path --------------> ${0%/*} "
echo "# my name ------------------> ${0##*/} "
echo
exit
# ------------- CALLED ------------- #
# Notice on the next line, the first argument is called within double,
# and single quotes, since it contains two words
$ /misc/shell_scripts/check_root/show_parms.sh "'hello there'" "'william'"
# ------------- RESULTS ------------- #
# arguments called with ---> 'hello there' 'william'
# $1 ----------------------> 'hello there'
# $2 ----------------------> 'william'
# path to me --------------> /misc/shell_scripts/check_root/show_parms.sh
# parent path -------------> /misc/shell_scripts/check_root
# my name -----------------> show_parms.sh
# ------------- END ------------- #
使用bash> = 3,以下工作:
$ ./s 0 is: ./s BASH_SOURCE is: ./s $ . ./s 0 is: bash BASH_SOURCE is: ./s $ cat s #!/bin/bash printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
如果脚本名称中包含空格,则更健壮的方法是使用"$0"
或"$(basename "$0")"
- 或在MacOS上:"$(basename \"$0\")"
.这可以防止名称被破坏或以任何方式解释.通常,优良作法是始终在shell中引用变量名称.
$BASH_SOURCE
在获取脚本时给出正确的答案.
但是这包括路径以便仅获取脚本文件名,使用:
$(basename $BASH_SOURCE)
如果你想要它没有路径那么你会使用 ${0##*/}
要回答Chris Conway,在Linux上(至少)你会这样做:
echo $(basename $(readlink -nf $0))
readlink打印出符号链接的值.如果它不是符号链接,则打印文件名.-n告诉它不要打印换行符.-f告诉它完全遵循链接(如果符号链接是指向另一个链接的链接,它也将解析该链接).
我发现此行始终有效,无论文件是源还是作为脚本运行.
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
如果你想按照readlink
上面提到的路径使用符号链接,递归或非递归.
使用BASH_SOURCE
环境变量及其关联来解释单行工作的原因FUNCNAME
.
BASH_SOURCE
一个数组变量,其成员是源文件名,其中定义了FUNCNAME数组变量中相应的shell函数名.shell函数$ {FUNCNAME [$ i]}在$ {BASH_SOURCE [$ i]}文件中定义,并从$ {BASH_SOURCE [$ i + 1]}调用.
FUNCNAME
一个数组变量,包含当前在执行调用堆栈中的所有shell函数的名称.索引为0的元素是当前正在执行的shell函数的名称.最底部的元素(索引最高的元素)是"main".此变量仅在执行shell函数时存在.对FUNCNAME的分配无效并返回错误状态.如果未设置FUNCNAME,则会丢失其特殊属性,即使它随后被重置.
此变量可与BASH_LINENO和BASH_SOURCE一起使用.FUNCNAME的每个元素在BASH_LINENO和BASH_SOURCE中都有对应的元素来描述调用堆栈.例如,$ {FUNCNAME [$ i]}是从行号$ {BASH_LINENO [$ i]}的$ {BASH_SOURCE [$ i + 1]}调用的.内置调用者使用此信息显示当前调用堆栈.
[来源:Bash手册]
这些答案对于他们陈述的情况是正确的,但如果您使用'source'关键字从另一个脚本运行脚本(以便它在同一个shell中运行),则仍然存在问题.在这种情况下,您将获得$ 0的调用脚本.在这种情况下,我认为不可能获得脚本本身的名称.
这是一个边缘案例,不应该认真对待.如果直接从另一个脚本运行脚本(没有'source'),使用$ 0将起作用.
回复:上面的Tanktalus(接受)回答,一个稍微清洁的方法是使用:
me=$(readlink --canonicalize --no-newline $0)
如果您的脚本来自另一个bash脚本,您可以使用:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
我同意如果您的目标是向用户提供反馈,则解除引用符号链接会很困惑,但有时您需要将规范名称添加到脚本或其他文件中,这是最好的方式,imo.
由于一些评论询问了没有扩展名的文件名,下面是一个如何实现的例子:
FileName=${0##*/} FileNameWithoutExtension=${FileName%.*}
请享用!
如果你的调用shell脚本喜欢
/home/mike/runme.sh
$ 0是全名
/home/mike/runme.sh
basename $ 0将获取基本文件名
runme.sh
你需要将这个基本名称放入一个变量中
filename=$(basename $0)
并添加您的其他文字
echo "You are running $filename"
所以你的脚本喜欢
/home/mike/runme.sh #!/bin/bash filename=$(basename $0) echo "You are running $filename"
您可以使用$ 0来确定您的脚本名称(使用完整路径) - 要获取脚本名称,您只能修改该变量
basename $0
this="$(dirname "$(realpath "$BASH_SOURCE")")"
这解析了符号链接(realpath就是这样),处理空格(双引号这样做),即使在sourced(./myscript)或其他脚本调用($ BASH_SOURCE处理它)时也会找到当前的脚本名称.毕竟,最好将它保存在环境变量中以便重复使用或在其他地方轻松复制(this =)...