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

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

就像如果我的脚本在文件runme.sh中,那么我如何在不硬编码的情况下显示“您正在运行runme.sh”消息?

584696 次浏览
me=`basename "$0"`

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

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

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


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

Echo"你正在运行0美元"

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

basename $0

如果脚本名称中有空格,更健壮的方法是使用"$0""$(basename "$0")"-或在MacOS:"$(basename \"$0\")"上。这可以防止名称以任何方式被破坏或解释。一般来说,在shell中始终双引号变量名称是一种很好的做法。

要回答克里斯康威,Linux(至少)你会这样做:

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

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

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

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

这是一个边缘情况,不应该太认真。如果您直接从另一个脚本运行脚本(没有“源”),使用0美元就可以了。

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

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

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

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

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

我同意,如果您的目标是向用户提供反馈,那么取消引用符号链接会令人困惑,但有时您确实需要将规范名称获取到脚本或其他文件中,这是最好的方法,imo。

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

我从另一个堆栈溢出问题Bash脚本可以告诉它存储在哪个目录中吗?中得到了上述内容,但我认为它对这个主题也很有用。

$BASH_SOURCE在寻找脚本时给出了正确的答案。

但是,这包括路径,因此要仅获取脚本文件名,请使用:

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

这会解析符号链接(real path会这样做),处理空格(双引号会这样做),并且即使来源(…/myscript)或被其他脚本调用($BASH_SOURCE处理)也会找到当前脚本名称。

我发现这一行始终有效,无论文件是作为脚本获取还是作为脚本运行。

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_SOURCE[$i+1]}中的行号${BASH_LINENO[$i]}调用的。调用者内置程序使用此信息显示当前调用堆栈。

[来源:Bash手册]

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

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

干杯

像这样的东西?

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

如果调用外壳脚本,如

/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"
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
&& readlink ${BASH_SOURCE[0]} \
|| echo ${BASH_SOURCE[0]}`")"

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

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

如果您使用像/path/to/script.sh这样的路径调用脚本,那么$0也会给出带有路径的文件名。在这种情况下,需要使用$(basename $0)来仅获取脚本文件名。

由于一些评论询问没有扩展名的文件名,这里有一个如何实现的示例:

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

好好享受!

这是我想出的,灵感来自DimitreRadoulov的答案(顺便说一句,我投了赞成票)

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


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

不管你怎么称呼你的剧本

. path/to/script.sh

./path/to/script.sh

简短,清晰,简单,在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.

这适用于./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"

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

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

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

然后像这样从终端跑出来

./file_name.sh