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

Ma9*_*9uS 567 linux bash shell scripting

如何在脚本本身中确定Bash脚本文件的名称?

就像我的脚本在文件中一样runme.sh,那么我怎么能让它显示"你正在运行runme.sh"的消息而没有硬编码?

Tan*_*lus 592

me=`basename "$0"`
Run Code Online (Sandbox Code Playgroud)

通过符号链接阅读,通常不是你想要的(你通常不想以这种方式混淆用户),试试:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
Run Code Online (Sandbox Code Playgroud)

IMO,这会产生令人困惑的输出."我跑了foo.sh,但它说我正在运行bar.sh!?一定是个bug!" 此外,具有不同名称的符号链接的目的之一是根据其所称的名称提供不同的功能(在某些平台上考虑gzip和gunzip).

  • 对于源而不是被调用的脚本不起作用. (73认同)
  • $ 0为您提供调用脚本的名称,而不是实际脚本文件的实际路径. (32认同)
  • -1,1.readlink将只传输一个符号链接,2.第一个例子中的`$ 0`受到单词拆分的影响,3.`$ 0`传递给basename,readlink和echo在一个允许它的位置作为命令行开关处理.我建议改为"我= $(basename - "$ 0")`或更高效,牺牲可读性,"我= $ {0 ##*/}.对于符号链接,`me = $(basename - "$(readlink -f - "$ 0")")`假设gnu utils,否则它将是一个非常长的脚本,我不会在这里写. (8认同)
  • 除非你通过符号链接调用,否则它可以工作.但是,即便如此,它通常也是你想要的,IME. (3认同)
  • @Charles Duffy:请参阅下面的[Dimitre Radoulov的答案](http://stackoverflow.com/questions/192319/in-the-bash-script-how-do-i-know-the-script-file-name/639500# 639500)。 (2认同)

Bil*_*dez 230

# ------------- 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 ------------- #

  • @NickC见[**子串删除**](http://tldp.org/LDP/abs/html/string-manipulation.html) (11认同)
  • `$ {0%/*}`和`$ {0 ##*/}`语法如何工作? (8认同)

Dim*_*lov 187

使用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"
Run Code Online (Sandbox Code Playgroud)

  • 大!这是适用于./scrip.sh和source ./script.sh的答案 (23认同)
  • 这就是我想要的,并且很容易使用"`dirname $ BASE_SOURCE`"来获取脚本所在的目录. (4认同)
  • 在编写自删除脚本时,我几乎很难理解到这种差异。幸运的是,“ rm”被别名为“ rm -i” :) (2认同)

Jos*_*Lee 67

如果脚本名称中包含空格,则更健壮的方法是使用"$0""$(basename "$0")"- 或在MacOS上:"$(basename \"$0\")".这可以防止名称被破坏或以任何方式解释.通常,优良作法是始终在shell中引用变量名称.

  • +1直接回答+简洁.如果需要符号链接功能我建议看:Travis B. Hartwell的回答. (2认同)

小智 65

$BASH_SOURCE 在获取脚本时给出正确的答案.

但是这包括路径以便仅获取脚本文件名,使用:

$(basename $BASH_SOURCE) 
Run Code Online (Sandbox Code Playgroud)

  • @AndreasM.Oberheim `basename` 的缺点是必须分叉一个单独的进程,而 `##*/` 只是 bash 自己的处理。不过,您仍然可以使用“$BASH_SOURCE”:“${BASH_SOURCE[0]##*/}” (5认同)
  • 恕我直言,这个答案是最好的答案,因为该解决方案使用了自记录代码。$ BASH_SOURCE完全可以理解,无需阅读任何文档,而例如$ {0 ## * /}则不是 (2认同)

Mr.*_*rat 24

如果你想要它没有路径那么你会使用 ${0##*/}


Tra*_*ell 19

要回答Chris Conway,在Linux上(至少)你会这样做:

echo $(basename $(readlink -nf $0))
Run Code Online (Sandbox Code Playgroud)

readlink打印出符号链接的值.如果它不是符号链接,则打印文件名.-n告诉它不要打印换行符.-f告诉它完全遵循链接(如果符号链接是指向另一个链接的链接,它也将解析该链接).

  • -n 是无害的,但不是必需的,因为 $(...) 结构会修剪它。 (2认同)

gkb*_*986 14

我发现此行始终有效,无论文件是源还是作为脚本运行.

echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
Run Code Online (Sandbox Code Playgroud)

如果你想按照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手册]

  • 如果你从一个交互式会话中获取文件`a`(假设`a`的内容是'echo'$ {BASH_SOURCE [$ {#BASH_SOURCE [@]} - 1]}"`),那么它会起作用给你一个路径.但是如果你用`source a`编写一个脚本`b`并运行`./ b`,它将返回`b`的路径. (2认同)

小智 12

这些答案对于他们陈述的情况是正确的,但如果您使用'source'关键字从另一个脚本运行脚本(以便它在同一个shell中运行),则仍然存在问题.在这种情况下,您将获得$ 0的调用脚本.在这种情况下,我认为不可能获得脚本本身的名称.

这是一个边缘案例,不应该认真对待.如果直接从另一个脚本运行脚本(没有'source'),使用$ 0将起作用.

  • 你有一个很好的观点.不是边缘情况IMO.但有一个解决方案:见[Dimitre Radoulov上面的答案](http://stackoverflow.com/questions/192319/in-the-bash-script-how-do-i-know-the-script-file-name/ 639500#639500) (2认同)

sim*_*mon 9

回复:上面的Tanktalus(接受)回答,一个稍微清洁的方法是使用:

me=$(readlink --canonicalize --no-newline $0)
Run Code Online (Sandbox Code Playgroud)

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

me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Run Code Online (Sandbox Code Playgroud)

我同意如果您的目标是向用户提供反馈,则解除引用符号链接会很困惑,但有时您需要将规范名称添加到脚本或其他文件中,这是最好的方式,imo.


Sim*_*tes 9

由于一些评论询问了没有扩展名的文件名,下面是一个如何实现的例子:

FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Run Code Online (Sandbox Code Playgroud)

请享用!

  • @RobertLugg:它被称为“bash 参数替换”,如果您搜索该术语,应该有大量材料:) (2认同)

小智 8

如果你的调用shell脚本喜欢

/home/mike/runme.sh
Run Code Online (Sandbox Code Playgroud)

$ 0是全名

 /home/mike/runme.sh
Run Code Online (Sandbox Code Playgroud)

basename $ 0将获取基本文件名

 runme.sh
Run Code Online (Sandbox Code Playgroud)

你需要将这个基本名称放入一个变量中

filename=$(basename $0)
Run Code Online (Sandbox Code Playgroud)

并添加您的其他文字

echo "You are running $filename"
Run Code Online (Sandbox Code Playgroud)

所以你的脚本喜欢

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


Vol*_*lkA 7

您可以使用$ 0来确定您的脚本名称(使用完整路径) - 要获取脚本名称,您只能修改该变量

basename $0
Run Code Online (Sandbox Code Playgroud)


jca*_*314 6

this="$(dirname "$(realpath "$BASH_SOURCE")")"
Run Code Online (Sandbox Code Playgroud)

这解析了符号链接(realpath就是这样),处理空格(双引号这样做),即使在sourced(./myscript)或其他脚本调用($ BASH_SOURCE处理它)时也会找到当前的脚本名称.毕竟,最好将它保存在环境变量中以便重复使用或在其他地方轻松复制(this =)...

  • 仅供参考`realpath`不是内置的BASH命令.它是一个独立的可执行文件,仅在某些发行版中可用 (3认同)

Nis*_*ant 6

这适用于./self.sh, ~/self.sh, source self.sh, source ~/self.sh

#!/usr/bin/env bash

self=$(readlink -f "${BASH_SOURCE[0]}")
basename=$(basename "$self")

echo "$self"
echo "$basename"
Run Code Online (Sandbox Code Playgroud)

积分:我结合了多个答案来得到这个答案。

  • `$(readlink -f "${BASH_SOURCE[0]}")` 仅在您使用 bash 时才有效。`$(readlink -f "${BASH_SOURCE:-$0}")` 无论如何都可以工作。 (3认同)