首页 文章

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

提问于
浏览
471

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

就像我的脚本在文件 runme.sh 中一样,那么如何在没有硬编码的情况下显示"You are running runme.sh"消息呢?

22 回答

  • 6

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

    basename $0
    
  • 21

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

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

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

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

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

  • 5

    感谢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
    }
    

    干杯

  • 19

    $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对他想要的东西有点模棱两可 .

  • 0

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

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

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

  • 0

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

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

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

  • 13

    这是我提出的,受到_128088的答案的启发(顺便提一下,我赞成) .

    script="$BASH_SOURCE"
    [ -z "$BASH_SOURCE" ] && script="$0"
    
    echo "Called $script with $# argument(s)"
    

    不管你调用脚本的方式如何

    . path/to/script.sh
    

    要么

    ./path/to/script.sh
    
  • 0
    echo "$(basename "`test -L ${BASH_SOURCE[0]} \
                       && readlink ${BASH_SOURCE[0]} \
                       || echo ${BASH_SOURCE[0]}`")"
    
  • 6

    像这样的东西?

    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
    
  • 497

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

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

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

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

  • 60

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

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

  • 207

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

  • 11
    me=`basename "$0"`
    

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

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

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

  • 2
    # ------------- 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 ------------- #
    
  • -5

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

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

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

    $(basename $BASH_SOURCE)
    
  • 57

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

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

  • 1

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

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

    请享用!

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

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

  • 8

    echo“你正在运行0美元”

相关问题