如何获取 shell 脚本自身文件名?
- 0次
- 2021-07-02 15:15:14
- idczone
比如脚本 abc.sh ,在这个脚本里,如何获取自身文件名 abc.sh
$0
echo $(basename $0)
感谢,两种方法都可行
在这边如此容易的知识点,我找了好久 QAQ
$0 是一个变量,保存了执行文件的文件名,相当于 C 语言中的 argv[0]
楼上还不够完全正确
应该是 echo $BASH_SOURCE
如果是 $0 的话, source abc.sh 就会出错了
还有一种情况$0 会出错,就是 cat abc.sh | bash
一般 $(basename $0) 比如脚本在 /root 目录下 脚本名为 abc.sh 全路径运行 $0 是 /root/abc.sh 当前目录运行时 ./abc.sh basename 取最后一个文件名
如果是符号链接,$0 也不准
依楼上各位所言,确实没有一种很好的方法来确定脚本自身文件名。
其实原理很简单。
因为维度不一样, shell 脚本运行的时候是无法直接获得比自己高一维度的信息的。
就像虚拟机里面运行的程序不知道自己是在虚拟机里面跑一个道理
$ 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
赞
$0 是命令行里面的执行文件
${BASH_SOURCE[0]} 才是当前执行文件
比如命令行执行 0.sh 然后 0.sh 里面 include 1.sh
那么 1.sh 里面的 $0 对应的是 0.sh, ${BASH_SOURCE[0]} 才是 1.sh
echo $0| awk -F "/" { print $NF }
没试过,不知有效不
echo $0| awk -F "/" '{ print $NF }'
忘打引号了
冒个泡,有道理啊。我调试 shell 实在麻烦。
涨姿势。不过楼主获取自身文件名做什么?
realpath path/to/filename
这个也很有用 ,我也曾经找了很久.
给个建议,考虑这么多蛋疼的、少见的使用情形,不如直接来个来个运维规范。
只让 ./xxx.sh 来运行,一切不是都解决了吗?
当然,规范这事有时很难做,但是我们不是还可以引导么?
脚本开头统一 , 给出去就是一个带着 x 权限的没有后缀的文件。我想面对这样一个文件没多少人会敢直接 sh XXX 来瞎执行
PS :被各路运维 sh XXX.sh 搞得实在烦了,好端端的 bash 脚本,非要拿 dash / bash posix 模式来跑,不出错才怪。
做了个测试
getname.sh:
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
C 的 argv[0],哈哈哈……
main.c:
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:
_BSD_SOURCE
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:
[email&/tmp/main
Hi, argv[0]
/tmp/print_argv_0
弱弱的 提一句: 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)
```
又整理了一下:
```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 内置方法, 终于解决了我多年的疑问了.