如何获取 shell 脚本自身文件名? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
Devin
V2EX    Linux

如何获取 shell 脚本自身文件名?

  •  
  •   Devin Aug 30, 2016 14136 views
    This topic created in 3529 days ago, the information mentioned may be changed or developed.
    比如脚本 abc.sh ,在这个脚本里,如何获取自身文件名 abc.sh
    22 replies    2021-03-04 20:59:14 +08:00
    bjzhou1990
        1
    bjzhou1990  
       Aug 30, 2016   1
    $0
    lxy42
        2
    lxy42  
       Aug 30, 2016   1
    echo $(basename $0)
    Devin
        3
    Devin  
    OP
       Aug 30, 2016
    @lxy42
    @bjzhou1990
    感谢,两种方法都可行
    在这边如此容易的知识点,我找了好久 QAQ
    lxy42
        4
    lxy42  
       Aug 30, 2016   1
    @Devin $0 是一个变量,保存了执行文件的文件名,相当于 C 语言中的 argv[0]
    fool
        5
    fool  
       Aug 30, 2016   1
    楼上还不够完全正确

    应该是 echo $BASH_SOURCE

    如果是 $0 的话, source abc.sh 就会出错了
    yaxin
        6
    yaxin  
       Aug 30, 2016   1
    还有一种情况$0 会出错,就是 cat abc.sh | bash
    zerofiny
        7
    zerofiny  
       Aug 30, 2016   1
    一般 $(basename $0) 比如脚本在 /root 目录下 脚本名为 abc.sh 全路径运行 $0 是 /root/abc.sh 当前目录运行时 ./abc.sh basename 取最后一个文件名
    wsy2220
        8
    wsy2220  
       Aug 30, 2016 via Android   1
    如果是符号链接,$0 也不准
    fiht
        9
    fiht  
       Aug 30, 2016   1
    依楼上各位所言,确实没有一种很好的方法来确定脚本自身文件名。
    其实原理很简单。
    因为维度不一样, shell 脚本运行的时候是无法直接获得比自己高一维度的信息的。
    就像虚拟机里面运行的程序不知道自己是在虚拟机里面跑一个道理
    lrz0lrz
        10
    lrz0lrz  
       Aug 30, 2016   6
    $ cat abc.sh
    echo $0
    echo $BASH_SOURCE
    $ ./abc.sh
    ./abc.sh
    ./abc.sh
    $ source abc.sh
    bash
    abc.sh
    $ cat abc.sh |bash
    bash

    $ ~/temp/abc.sh
    /home/xxx/temp/abc.sh
    /home/xxx/temp/abc.sh
    vus520
        11
    vus520  
       Aug 30, 2016
    @lrz0lrz
    SoloCompany
        12
    SoloCompany  
       Aug 31, 2016   1
    $0 是命令行里面的执行文件
    ${BASH_SOURCE[0]} 才是当前执行文件

    比如命令行执行 0.sh 然后 0.sh 里面 include 1.sh
    那么 1.sh 里面的 $0 对应的是 0.sh, ${BASH_SOURCE[0]} 才是 1.sh
    Vicer
        13
    Vicer  
       Aug 31, 2016 via Android
    echo $0| awk -F "/" { print $NF }
    没试过,不知有效不
    Vicer
        14
    Vicer  
       Aug 31, 2016 via Android   1
    echo $0| awk -F "/" '{ print $NF }'
    忘打引号了
    jyf007
        15
    jyf007  
       Aug 31, 2016 via Android
    冒个泡,有道理啊。我调试 shell 实在麻烦。
    clearbug
        16
    clearbug  
       Aug 31, 2016 via Android
    涨姿势。不过楼主获取自身文件名做什么?
    GPU
        17
    GPU  
       Aug 31, 2016   1
    realpath path/to/filename

    这个也很有用 ,我也曾经找了很久.
    wweir
        18
    wweir  
       Aug 31, 2016   2
    给个建议,考虑这么多蛋疼的、少见的使用情形,不如直接来个来个运维规范。
    只让 ./xxx.sh 来运行,一切不是都解决了吗?

    当然,规范这事有时很难做,但是我们不是还可以引导么?
    脚本开头统一 #!/bin/bash , 给出去就是一个带着 x 权限的没有后缀的文件。我想面对这样一个文件没多少人会敢直接 sh XXX 来瞎执行

    PS :被各路运维 sh XXX.sh 搞得实在烦了,好端端的 bash 脚本,非要拿 dash / bash posix 模式来跑,不出错才怪。
    araraloren
        19
    araraloren  
       Aug 31, 2016   1
    做了个测试


    getname.sh:
    #!/usr/bin/env bash

    echo `basename $0`
    echo `basename ${BASH_SOURCE}`

    getname --> getname.sh , getname 是一个软链接

    ./getname | bash ./getname | sh ./getname

    getname
    getname

    ./getname.sh | bash ./getname.sh | ./getname.sh

    getname.sh
    getname.sh

    source ./getname

    bash
    getname

    source ./getname.sh

    bash
    getname.sh
    extreme
        20
    extreme  
       Aug 31, 2016   1
    C 的 argv[0],哈哈哈……


    main.c:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(void) {
    char *argv[] = {"Hi, argv[0]", "argv[1]", NULL}, *env[] = {NULL};
    if (execve("./print_argv_0", argv, env) < 0) {
    perror("execve()");
    return -1;
    }
    return 0;
    }




    print_argv_0.c:

    #define _BSD_SOURCE

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

    int main(int argc, char *argv[]) {
    int pid = getpid();
    char buffer[100], result_buffer[100];
    printf("%s\n", argv[0]);
    sprintf(buffer, "/proc/%d/exe", pid);
    printf("%s\n", realpath(buffer, result_buffer));
    return 0;
    }


    Example output:
    user@hostname:/tmp$ /tmp/main
    Hi, argv[0]
    /tmp/print_argv_0
    ayanmw
        21
    ayanmw  
       Mar 4, 2021
    弱弱的 提一句: caller
    bash 有一个命令 caller ,可以获得 调用堆栈的 line filename
    所以 用 caller , 基本上 就 OK 了

    ```shell
    getFileName(){
    fname=$(echo $(caller)|cut -d ' ' -f 2-)
    if test -f $fname;then
    link=$(readlink $fname);
    if test -z "$link";then echo $(basename $fname);return 0;fi
    echo $(basename $(readlink $fname));
    return 0
    fi
    echo $fname
    }

    echo fileName=$(getFileName)

    ```
    ayanmw
        22
    ayanmw  
       Mar 4, 2021
    @ayanmw 又整理了一下:
    ```bash

    getFileName(){
    call=$(caller)
    if test -z "$call";then
    echo $0
    return 0
    fi
    fname=$(echo $(caller)|cut -d ' ' -f 2-)
    if test -f $fname;then
    link=$(readlink $fname);
    if test -z "$link";then
    if test -f $fname;then
    echo $(basename $fname);return 0;
    fi
    echo $fname;return 0;
    fi
    echo $(basename $(readlink $fname));
    return 0
    fi
    echo $fname
    }

    echo fileName=$(getFileName)

    ```

    函数可以在任意文件, 你只需要 `. libFunc.sh` 或者 `source libFunc.sh` 包含这个函数, 在任何地方调用
    `echo fileName=$(getFileName)` 都可以获得 你当前所在的文件.

    caller 这个 bash 内置方法, 终于解决了我多年的疑问了.
    About     Help     Advertise     Blog     API     FAQ     Solana     1000 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 72ms UTC 19:27 PVG 03:27 LAX 12:27 JFK 15:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86