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

时间:2008-10-10 17:20:42

标签: linux bash shell scripting

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

就像我的脚本在文件runme.sh中一样,那么如何在没有硬编码的情况下显示“你正在运行runme.sh”消息呢?

25 个答案:

答案 0 :(得分:545)

me=`basename "$0"`

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

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

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


1 也就是说,要解析符号链接,以便当用户执行foo.sh实际上是bar.sh的符号链接时,您希望使用已解析的名称{{1而不是bar.sh

答案 1 :(得分:223)

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

答案 2 :(得分:178)

使用 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"

答案 3 :(得分:61)

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

答案 4 :(得分:60)

在获取脚本时,

$BASH_SOURCE会给出正确的答案。

然而,这包括仅获取脚本文件名的路径,请使用:

$(basename $BASH_SOURCE) 

答案 5 :(得分:24)

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

答案 6 :(得分:19)

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

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

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

答案 7 :(得分:13)

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

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手册]

答案 8 :(得分:11)

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

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

答案 9 :(得分:8)

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

FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}

享受!

答案 10 :(得分:8)

如果你的调用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"

答案 11 :(得分:8)

Re:上面的Tanktalus(已接受)答案,稍微更清洁的方法是使用:

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

如果您的脚本来自其他bash脚本,则可以使用:

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

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

答案 12 :(得分:7)

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

修剪该变量
basename $0

答案 13 :(得分:5)

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

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

答案 14 :(得分:3)

bash中,您可以使用$0获取脚本文件名。通常$1$2等用于访问CLI参数。同样$0是访问触发脚本的名称(脚本文件名)。

#!/bin/bash
echo "You are running $0"
...
...

如果使用/path/to/script.sh之类的路径调用脚本,则$0也会为文件名提供路径。在这种情况下,需要使用$(basename $0)来获取脚本文件名。

答案 15 :(得分:2)

感谢Bill Hernandez。我添加了一些我采用的偏好。

#!/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
}

干杯

答案 16 :(得分:1)

$0没有回答这个问题(据我了解)。演示:

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

如何让./linktoscript打印出script.sh

[编辑]在上面的评论中,每个@ephemient,虽然符号链接的东西可能看似人为,但有可能摆弄$0,使其不代表文件系统资源。 OP对他想要的东西有点模棱两可。

答案 17 :(得分:1)

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

答案 18 :(得分:0)

./self.sh~/self.shsource self.shsource ~/self.sh上可以正常使用:

#!/usr/bin/env bash

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

echo "$self"
echo "$basename"

信用:我结合了多个答案来得到这个答案。

答案 19 :(得分:0)

简短my_script.sh

#!/bin/bash

running_file_name=$(basename "$0")

echo "You are running '$running_file_name' file."

输出:

./my_script.sh
You are running 'my_script.sh' file.

答案 20 :(得分:0)

$0 将给出您正在运行的脚本的名称。创建脚本文件并添加以下代码

#!/bin/bash
echo "Name of the file is $0"

然后像这样从终端运行

./file_name.sh

答案 21 :(得分:0)

这是我想到的,灵感来自Dimitre Radoulov的答案(顺便说一下,我赞成)

script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"

echo "Called $script with $# argument(s)"

不管您如何调用脚本

. path/to/script.sh

./path/to/script.sh

答案 22 :(得分:0)

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

我从另一个Stack Overflow问题 Can a Bash script tell what directory it's stored in? 得到了上述内容,但我认为它对此主题也很有用。

答案 23 :(得分:0)

echo“你正在运行$ 0”

答案 24 :(得分:-5)

这样的事情?

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