如何知道Bash脚本中的脚本文件名?

我怎样才能确定脚本本身内的Bash脚本文件的名称?

就像如果我的脚本在文件runme.sh ,那么我将如何使它显示“你正在运行runme.sh”消息,而不硬编码?

 me=`basename "$0"` 

对于通常不是你想要的符号链接(你通常不想用这种方式混淆用户),请尝试:

 me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")" 

国际海事组织,这将产生混乱的输出。 “我跑了foo.sh,但是这是说我正在运行bar.sh!?一定是个bug! 此外,具有不同名称符号链接的目的之一是提供基于名称的不同function(在某些平台上认为是gzip和gunzip)。

 #-------------脚本-------------#
#!/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
 #-------------调用-------------#

 #注意下一行,第一个参数在double内调用, 
 #和单引号,因为它包含两个单词

 $ /misc/shell_scripts/check_root/show_parms.sh“'hello there'”“'william'”

 #-------------结果-------------#

 #参数调用--->'你好'威廉'
 #$ 1 ---------------------->'你好'
 #$ 2 ---------------------->'william'
 #path to me --------------> /misc/shell_scripts/check_root/show_parms.sh
 #父path-------------> / misc / shell_scripts / check_root
 #我的名字-----------------> show_parms.sh

 #  -  -  -  -  -  - - 结束  -  -  -  -  -  - - #

随着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\")" 。 这可以防止名称受到任何forms的破坏或解释。 一般来说,总是在shell中双引号variables名是一个好习惯。

当采购脚本时, $BASH_SOURCE给出正确的答案。

然而,这包括path,所以只获得脚本文件名,使用:

 $(basename $BASH_SOURCE) 

要回答Chris Conway ,在Linux上(至less)你应该这样做:

 echo $(basename $(readlink -nf $0)) 

readlink输出一个符号链接的值。 如果不是符号链接,则会打印文件名。 -n告诉它不打印换行符。 -f告诉它完全遵循链接(如果一个符号链接是另一个链接的链接,它也可以解决这个问题)。

如果你想没有path,那么你会使用${0##*/}

这些答案对于它们的状态是正确的,但如果使用“source”关键字从另一个脚本运行脚本(以便它在同一个shell中运行),则仍然存在问题。 在这种情况下,你得到$ 0的调用脚本。 在这种情况下,我不认为有可能获得脚本本身的名字。

这是一个边缘情况,不应该认真对待。 如果直接从另一个脚本运行脚本(没有“源代码”),则使用$ 0将起作用。

我发现这行总是工作,无论文件是源代码还是作为脚本运行。

 echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}" 

如果你想遵循符号链接,使用上面获得的path的readlink ,recursion或非recursion。

单行工作的原因是通过使用BASH_SOURCE环境variables及其关联的FUNCNAME

BASH_SOURCE

一个数组variables,其成员是源文件名,其中定义了FUNCNAME数组variables中相应的shell函数名。 shell函数$ {FUNCNAME [$ i]}在文件$ {BASH_SOURCE [$ i]}中定义,并从$ {BASH_SOURCE [$ i + 1]}中调用。

FUNCNAME

包含当前执行调用堆栈中的所有shell函数的名称的数组variables。 索引为0的元素是任何当前正在执行的shell函数的名称。 最底层的元素(索引最高的元素)是“主”。 这个variables只有在shell函数执行时才存在。 对FUNCNAME的分配无效,并返回错误状态。 如果FUNCNAME未设置,即使随后重置,它也会失去其特殊属性。

这个variables可以和BASH_LINENO和BASH_SOURCE一起使用。 FUNCNAME的每个元素在BASH_LINENO和BASH_SOURCE中都有对应的元素来描述调用堆栈。 例如,$ {FUNCNAME [$ i]}在行号$ {BASH_LINENO [$ i]}中的文件$ {BASH_SOURCE [$ i + 1]}被调用。 调用者内build使用此信息显示当前的调用堆栈。

[来源:Bash手册]

回复:Tanktalus的(接受)上面的答案,稍微更简洁的方法是使用:

 me=$(readlink --canonicalize --no-newline $0) 

如果您的脚本来自另一个bash脚本,则可以使用:

 me=$(readlink --canonicalize --no-newline $BASH_SOURCE) 

我同意,如果您的目标是向用户提供反馈,那么解引用符号链接会是一个混淆,但是在某些情况下,您确实需要将脚本或其他文件的规范名称获得,这是最好的方法。

您可以使用$ 0来确定您的脚本名称(使用完整path) – 只有您可以使用修剪该variables才能获取脚本名称

 basename $0 
 this="$(dirname "$(realpath "$BASH_SOURCE")")" 

这解决了符号链接(真实path),处理空格(双引号这样做),并将find当前的脚本名称,即使源(。./myscript)或由其他脚本调用($ BASH_SOURCE句柄)。 毕竟,这是很好的保存在一个环境variables重用或容易复制在别处(这=)…

如果你的调用shell脚本像

 /home/mike/runme.sh 

$ 0是全名

  /home/mike/runme.sh 

basename $ 0将获得基本文件名称

  runme.sh 

你需要把这个基本名称放入一个variables中

 filename=$(basename $0) 

并添加您的附加文字

 echo "You are running $filename" 

所以你的脚本就像

 /home/mike/runme.sh #!/bin/bash filename=$(basename $0) echo "You are running $filename" 

信息感谢比尔·埃尔南德斯。 我添加了一些我正在采用的偏好。

 #!/bin/bash function Usage(){ echo " Usage: show_parameters [ arg1 ][ arg2 ]" } [[ ${#2} -eq 0 ]] && Usage || { echo echo "# arguments called with ----> ${@} " echo "# \$1 -----------------------> $1 " echo "# \$2 -----------------------> $2 " echo "# path to me ---------------> ${0} " | sed "s/$USER/\$USER/g" echo "# parent path --------------> ${0%/*} " | sed "s/$USER/\$USER/g" echo "# my name ------------------> ${0##*/} " echo } 

干杯

 echo "$(basename "`test -L ${BASH_SOURCE[0]} \ && readlink ${BASH_SOURCE[0]} \ || echo ${BASH_SOURCE[0]}`")" 

$0不回答这个问题(据我所知)。 示范:

 $ cat script.sh
 #!  / bin / sh的
 echo`basename $ 0`
 $ ./script.sh 
 script.sh
 $ ln script.sh linktoscript
 $ ./linktoscript 
 linktoscript

如何得到./linktoscript输出script.sh

[编辑]上面的注释中的每个@ephemient,虽然符号链接的东西可能看起来有些devise,但可能摆弄$0 ,使它不代表文件系统资源。 OP对他想要的东西有点含糊不清。

 DIRECTORY=$(cd `dirname $0` && pwd) 

我从另一个堆栈溢出问题得到了上述问题, Bash脚本可以告诉它存储在什么目录? ,但是我认为这对于这个主题也是有用的。

回声“你正在运行$ 0”

像这样的东西?

 export LC_ALL=en_US.UTF-8 #!/bin/bash #!/bin/sh #---------------------------------------------------------------------- start_trash(){ ver="htrash.sh v0.0.4" $TRASH_DIR # url to trash $MY_USER $TRASH_SIZE # Show Trash Folder Size echo "Would you like to empty Trash [y/n]?" read ans if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ] then echo "'yes'" cd $TRASH_DIR && $EMPTY_TRASH fi if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ] then echo "'no'" fi return $TRUE } #----------------------------------------------------------------------- start_help(){ echo "HELP COMMANDS-----------------------------" echo "htest www open a homepage " echo "htest trash empty trash " return $TRUE } #end Help #-----------------------------------------------# homepage="" return $TRUE } #end cpdebtemp # -Case start # if no command line arg given # set val to Unknown if [ -z $1 ] then val="*** Unknown ***" elif [ -n $1 ] then # otherwise make first arg as val val=$1 fi # use case statement to make decision for rental case $val in "trash") start_trash ;; "help") start_help ;; "www") firefox $homepage ;; *) echo "Sorry, I can not get a $val for you!";; esac # Case stop