如何获取 shell 脚本自身文件名? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Devin
V2EX    Linux

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

  •  
  •   Devin 2016-08-30 17:47:17 +08:00 13781 次点击
    这是一个创建于 3332 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如脚本 abc.sh ,在这个脚本里,如何获取自身文件名 abc.sh
    22 条回复    2021-03-04 20:59:14 +08:00
    bjzhou1990
        1
    bjzhou1990  
       2016-08-30 17:51:18 +08:00   1
    $0
    lxy42
        2
    lxy42  
       2016-08-30 17:51:24 +08:00   1
    echo $(basename $0)
    Devin
        3
    Devin  
    OP
       2016-08-30 17:55:26 +08:00
    @lxy42
    @bjzhou1990
    感谢,两种方法都可行
    在这边如此容易的知识点,我找了好久 QAQ
    lxy42
        4
    lxy42  
       2016-08-30 18:08:57 +08:00   1
    @Devin $0 是一个变量,保存了执行文件的文件名,相当于 C 语言中的 argv[0]
    fool
        5
    fool  
       2016-08-30 18:45:30 +08:00   1
    楼上还不够完全正确

    应该是 echo $BASH_SOURCE

    如果是 $0 的话, source abc.sh 就会出错了
    yaxin
        6
    yaxin  
       2016-08-30 18:52:10 +08:00   1
    还有一种情况$0 会出错,就是 cat abc.sh | bash
    hasdream
        7
    hasdream  
       2016-08-30 19:01:18 +08:00   1
    一般 $(basename $0) 比如脚本在 /root 目录下 脚本名为 abc.sh 全路径运行 $0 是 /root/abc.sh 当前目录运行时 ./abc.sh basename 取最后一个文件名
    wsy2220
        8
    wsy2220  
       2016-08-30 19:01:34 +08:00 via Android   1
    如果是符号链接,$0 也不准
    fiht
        9
    fiht  
       2016-08-30 21:02:59 +08:00   1
    依楼上各位所言,确实没有一种很好的方法来确定脚本自身文件名。
    其实原理很简单。
    因为维度不一样, shell 脚本运行的时候是无法直接获得比自己高一维度的信息的。
    就像虚拟机里面运行的程序不知道自己是在虚拟机里面跑一个道理
    lrz0lrz
        10
    lrz0lrz  
       2016-08-30 21:40:21 +08:00   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  
       2016-08-30 22:28:05 +08:00
    @lrz0lrz
    SoloCompany
        12
    SoloCompany  
       2016-08-31 00:07:02 +08:00   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  
       2016-08-31 01:25:29 +08:00 via Android
    echo $0| awk -F "/" { print $NF }
    没试过,不知有效不
    Vicer
        14
    Vicer  
       2016-08-31 01:28:02 +08:00 via Android   1
    echo $0| awk -F "/" '{ print $NF }'
    忘打引号了
    jyf007
        15
    jyf007  
       2016-08-31 06:44:37 +08:00 via Android
    冒个泡,有道理啊。我调试 shell 实在麻烦。
    clearbug
        16
    clearbug  
       2016-08-31 07:05:47 +08:00 via Android
    涨姿势。不过楼主获取自身文件名做什么?
    GPU
        17
    GPU  
       2016-08-31 08:54:02 +08:00   1
    realpath path/to/filename

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

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

    PS :被各路运维 sh XXX.sh 搞得实在烦了,好端端的 bash 脚本,非要拿 dash / bash posix 模式来跑,不出错才怪。
    araraloren
    &nbs;   19
    araraloren  
       2016-08-31 11:12:35 +08:00   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  
       2016-08-31 15:21:51 +08:00   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  
       2021-03-04 20:35:52 +08:00
    弱弱的 提一句: 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  
       2021-03-04 20:59:14 +08:00
    @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 内置方法, 终于解决了我多年的疑问了.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5814 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 03:06 PVG 11:06 LAX 20:06 JFK 23:06
    Do have faith in what you're doing.
    ubao 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