繁体   English   中英

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

[英]How do I know the script file name in a Bash script?

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

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

me=`basename "$0"`

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

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

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


1也就是说,是解决符号链接,这样当用户执行foo.sh实际上是一个符号链接bar.sh ,您希望使用的解析名称bar.sh而非foo.sh

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

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

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

$(basename $BASH_SOURCE) 

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

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

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

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

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

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

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

如果您想遵循符号链接, readlink在上面的路径上使用readlink递归或非递归。

单行工作的原因可以通过使用BASH_SOURCE环境变量及其关联的FUNCNAME

BASH_SOURCE

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

函数名

一个数组变量,包含当前在执行调用堆栈中的所有 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 手册]

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

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

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

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

享受!

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

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

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

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

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

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

这将解析符号链接(realpath 执行此操作)、处理空格(双引号执行此操作),并且即使在来源 (. ./myscript) 或由其他脚本调用($BASH_SOURCE 处理该)时也会找到当前脚本名称。 毕竟,最好将其保存在环境变量中以供重复使用或在其他地方轻松复制 (this=)...

您可以使用 $0 来确定您的脚本名称(带完整路径) - 只有您可以使用

basename $0

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

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

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

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之类的/path/to/script.sh调用脚本,则$0还将提供带有路径的文件名。 在这种情况下,需要使用$(basename $0)来获取脚本文件名。

$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对他想要的内容有点含糊。

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

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

干杯

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

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.

echo "你正在运行 $0"

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

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

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

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

然后像这样从终端运行

./file_name.sh

在所有情况下获取脚本或源脚本的“真实路径”:

fullname=$(readlink $0)  # Take care of  symbolic links
realpath=$(dirname $BASH_SOURCE) # TO handle sourced scripts
[ "$realpath" = '.' ] && realpath=${fullname%/*}

这是要生成的 bash 脚本(在新创建的“workdir”子目录和当前目录中的“ mytest ”中),一个 bash 脚本反过来将生成另一个脚本,该脚本将依次调用 bash 定义的函数....测试了许多启动它们的方法:

#!/bin/bash
##############################################################

ret=0

fullname=$(readlink $0)  # Take care of  symbolic links
realpath=$(dirname $BASH_SOURCE) # To handle sourced scripts
[ "$realpath" = '.' ] && realpath=${fullname%/*}

dirname=${fullname%/*}       # Get (most of the time) the dirname

fullname_withoutextension=${fullname%.*}

mkdir -p workdir
cat <<'EOD' > workdir/_script_.sh
#!/bin/bash
##############################################################

ret=0

fullname=$(readlink $0)  # Take care of  symbolic links
realpath=$(dirname $BASH_SOURCE) # To handle sourced scripts
[ "$realpath" = '.' ] && realpath=${fullname%/*}

dirname=${fullname%/*}       # Get (most of the time) the dirname

fullname_withoutextension=${fullname%.*}

echo
echo "# ------------- RESULTS ------------- #"
echo "# path to me (\$0)----------->  ${0}     "
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ----------------------->  $1       "
echo "# \$2 ----------------------->  $2       "
echo "# path to me (\$fullname)---->  ${fullname} "
echo "# parent path(\${0%/*})------>  ${0%/*}  "
echo "# parent path(\$dirname)----->  ${dirname} "
echo "# my name ----\${0##*/}------>  ${0##*/} "
echo "# my source -\${BASH_SOURCE}->  ${BASH_SOURCE} "
echo "# parent path(from BASH_SOURCE) -> $(dirname $BASH_SOURCE)"
echo "# my function name -\${FUNCNAME[0]}------>  ${FUNCNAME[0]}"
echo "# my source or script real path (realpath)------------------>  $realpath"
echo
[ "$realpath" = "workdir" ] || ret=1
[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "***********   ERROR  **********************************"
[ $ret = 0 ] || echo "*******************************************************"

show_params () {
        echo
        echo "# --- RESULTS FROM show_params() ---- #"
        echo "# path to me (\$0)----------->  ${0}     "
        echo "# arguments called with ---->  ${@}     "
        echo "# \$1 ----------------------->  $1       "
        echo "# \$2 ----------------------->  $2       "
        echo "# path to me (\$fullname)---->  ${fullname} "
        echo "# parent path(\${0%/*})------>  ${0%/*}  "
        echo "# parent path(\$dirname)----->  ${dirname} "
        echo "# my name ----\${0##*/}------>  ${0##*/} "
        echo "# my source -\${BASH_SOURCE}->  ${BASH_SOURCE} "
        echo "# parent path(from BASH_SOURCE) -> $(dirname $BASH_SOURCE)"
        echo "# my function name -\${FUNCNAME[0]}------>  ${FUNCNAME[0]}"
        echo "# my source or script real path (realpath)------------------>  $realpath"
        echo
        [ "$realpath" = "workdir" ] || ret=1
        [ $ret = 0 ] || echo "*******************************************************"
        [ $ret = 0 ] || echo "***********   ERROR  **********************************"
        [ $ret = 0 ] || echo "*******************************************************"

}
show_params "$@"

EOD

cat workdir/_script_.sh > workdir/_side_by_side_script_sourced.inc

cat <<'EOD' >> workdir/_script_.sh

echo "# . $realpath/_side_by_side_script_sourced.inc 'hello there' 'william'"
. $realpath/_side_by_side_script_sourced.inc 'hello there' 'william'

[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "***********   ERROR  **********************************"
[ $ret = 0 ] || echo "*******************************************************"
EOD

chmod +x  workdir/_script_.sh
[ -L _mytest_ ] && rm _mytest_
ln -s workdir/_script_.sh _mytest_

# ------------- CALLED ------------- #

called_by () {
        echo '=========================================================================='
        echo " Called by : " "$@"
        echo '=========================================================================='
        eval "$@"
}

called_by bash _mytest_
called_by ./_mytest_

called_by bash workdir/_script_.sh
called_by workdir/_script_.sh
called_by . workdir/_script_.sh


# ------------- RESULTS ------------- #

echo
echo
[ $ret = 0 ] || echo "*******************************************************"
[ $ret = 0 ] || echo "***********   ERROR  **********************************"
[ $ret = 0 ] || echo "*******************************************************"
echo
[ $ret = 0 ] && echo ".... location of scripts (\$realpath) should always be equal to $realpath, for all test cases at date".
echo

# ------------- END ------------- #

像这样的东西?

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM