在bash中获取脚本文件名
1. 概述
很多时候,我们需要从脚本本身中找到脚本的文件名。一种常见的用例是使用*–help*选项显示脚本的用法。
在本教程中,我们将讨论一些在*bash *中实现此目的的方法。
2. 使用basename命令
basename 命令允许我们从文件名中去除目录和后缀。 我们可以使用它来查找脚本的文件名:
$ cat dir1/dir2/find-script-name.sh
#!/bin/bash
echo "Script name =" $(basename "$0")
$ dir1/dir2/find-script-name.sh
Script name = find-script-name.sh
在此示例中,我们使用*$0和basename命令的组合来查找我们调用的脚本的文件名。$0* 是bash中的一个特殊变量,它表示具有相对路径的文件名。因此,我们使用basename命令从脚本的文件名中去除目录名。
3.使用参数扩展
我们还可以在bash中使用参数扩展 来查找脚本的文件名:
$ cat dir1/dir2/find-script-name.sh
#!/bin/bash
echo "Script name = ${0##*/}"
$ dir1/dir2/find-script-name.sh
Script name = find-script-name.sh
在此示例中,*${0##*/}*表示参数扩展。
4. 使用BASH_SOURCE环境变量
BASH_SOURCE 是bash中包含文件名的环境变量。我们可以将它与basename命令一起使用来获取脚本的文件名:
$ cat dir1/dir2/find-script-name.sh
#!/bin/bash
echo "Script name =" $(basename "${BASH_SOURCE}")
$ /dir1/dir2/find-script-name.sh
Script name = find-script-name.sh
5. 通过链接调用脚本时的问题
在 Linux 上,将文件链接到其他地方是一种常见操作,尤其是对于可执行文件。到目前为止,我们已经通过示例学习了三种从脚本本身中查找脚本文件名的方法。
接下来,让我们看看如果我们通过符号链接调用脚本,它们是否仍然有效。
首先,让我们创建一个包含这三种方法的新脚本:
$ cat dir1/dir2/find-script-name-all.sh
#!/bin/bash
echo 'Getting name by basename $0: ' $(basename "$0")
echo 'Getting name by ${0##*/}: ' ${0##*/}
echo 'Getting name by basename ${BASH_SOURCE}: ' $(basename "${BASH_SOURCE}")
接下来,让我们创建一个指向脚本的符号链接,并通过链接调用脚本:
$ ln -s dir1/dir2/find-script-name-all.sh i-am-a-link
$ ls -l i-am-a-link
lrwxrwxrwx 1 kent kent 33 Jan 24 23:10 i-am-a-link -> dir1/dir2/find-script-name-all.sh
$ ./i-am-a-link
Getting name by basename $0: i-am-a-link
Getting name by ${0##*/}: i-am-a-link
Getting name by basename ${BASH_SOURCE}: i-am-a-link
正如我们从上面的输出中看到的,所有三种方法都报告了链接的名称而不是真正的脚本名称。也就是说,所有方法都失败了。
接下来,让我们看看如何解决这个问题。
6. 使用 readlink命令
我们可以使用*readlink 命令来解决这个问题。让我们在find-script-name-all.sh*脚本中添加两个新命令:
$ cat dir1/dir2/find-script-name-all.sh
#!/bin/bash
echo 'Getting name by basename $0: ' $(basename "$0")
echo 'Getting name by ${0##*/}: ' ${0##*/}
echo 'Getting name by basename ${BASH_SOURCE}: ' $(basename "${BASH_SOURCE}")
echo '------ Using readlink ----- '
echo 'Getting name by basename $(readlink -f ${BASH_SOURCE}): ' $(basename "$(readlink -f "${BASH_SOURCE}")")
echo 'Getting name by basename $(readlink -f $0): ' $(basename "$(readlink -f "$0")")
在这里,我们使用带有-f选项的readlink*命令递归地跟踪每个符号链接*。
现在,让我们再次通过链接调用我们的脚本,看看我们是否可以获得真正的脚本文件名:
$ ./i-am-a-link
Getting name by basename $0: i-am-a-link
Getting name by ${0##*/}: i-am-a-link
## Getting name by basename ${BASH_SOURCE}: i-am-a-link
Getting name by basename $(readlink -f ${BASH_SOURCE}): find-script-name-all.sh
Getting name by basename $(readlink -f $0): find-script-name-all.sh
如上面的测试所示,带有readlink的新命令可以报告脚本的真实文件名。 此外,值得一提的是,如果我们直接调用脚本,readlink方法也可以工作:
$ dir1/dir2/find-script-name-all.sh
Getting name by basename $0: find-script-name-all.sh
Getting name by ${0##*/}: find-script-name-all.sh
## Getting name by basename ${BASH_SOURCE}: find-script-name-all.sh
Getting name by basename $(readlink -f ${BASH_SOURCE}): find-script-name-all.sh
Getting name by basename $(readlink -f $0): find-script-name-all.sh
因此,readlink方法是该问题的一般解决方案。