我一直在通过阅读优秀的教程和脚本来学习 shell 脚本。
我正在读这个我的世界初始化脚本,第一行让我印象深刻:
if [ -L $0 ]
then
source `readlink -e $0 | sed "s:[^/]*$:config:"`
else
source `echo $0 | sed "s:[^/]*$:config:"`
fi
因此,这些行在同一 shell 中启动名为“config”的脚本(其中存储所有配置值)。但是为什么,该脚本的作者不是直接启动文件(使用“源配置”之类的东西),而是读取原始脚本的名称(无论它是否是链接)并将结果发送到以sed
用“替换该名称”配置”?
答案1
使用源码
该命令source
不运行其他脚本。它只是将另一个脚本的内容拉入此脚本,然后运行其内容,就好像它最初是调用脚本的一部分一样。
它基本上是一种将其他脚本的内容包含到与您自己的脚本相同的范围中的机制。
使用读取链接
如果通过链接调用原始脚本,则存在此命令。
使用 sed
该脚本利用 sed 将调用脚本的名称转换为 name config
。
例子
假设我们有这个脚本,名为orig.bash
:
#!/bin/bash
printf "exectued as: %s\n" $0
cmd=$(readlink -e $0 | sed "s:[^/]*$:config:")
printf "sourcing as: %s\n" "$cmd"
这个程序会做两件事。
打印出的值
$0
printf "exectued as: %s\n" $0
readlink ...
打印命令的值cmd=$(readlink -e $0 | sed "s:[^/]*$:config:") printf "sourcing as: %s\n" "$cmd"
现在让我们创建一个指向该脚本的链接link2orig.bash
。所以我们的目录中现在有以下文件:
# creates link
$ ln -s orig.bash link2orig.bash
# results after
$ ls -l
total 4
lrwxrwxrwx 1 saml saml 9 Sep 5 06:23 link2orig.bash -> orig.bash
-rwxrwxr-x 1 saml saml 126 Sep 5 06:31 orig.bash
现在看看会发生什么
因此,现在当我们使用真实姓名或链接运行示例脚本时,我们仍然可以将 string 替换为调用者的参数config
。这是另一个包含我们正在采购的脚本的配置信息的文件。
$ ./orig.bash
executed as: ./orig.bash
sourcing as: /home/saml/tst/89518/config
$ ./link2orig.bash
executed as: ./link2orig.bash
sourcing as: /home/saml/tst/89518/config
如果您会注意到,这种方法的优点之一是它非常容忍以不同方式并从系统上的不同位置进行调用。
$ ../89518/orig.bash
executed as: ../89518/orig.bash
sourcing as: /home/saml/tst/89518/config
$ ../89518/link2orig.bash
executed as: ../89518/link2orig.bash
sourcing as: /home/saml/tst/89518/config
答案2
$0
是脚本的路径。它通常是脚本的完整路径(即绝对路径,以 开头/
)。在脚本可执行且以 shebang 行开头的常见情况下,路径将是完整路径。但是,如果显式调用 shell,$0
则为用户在命令行中键入的任何内容,其中可能不包含路径(使用cd somedir; bash minecraft
, $0
is minecraft
)。如果使用标准输入上的脚本调用 shell,则$0
是 shell 的名称或路径(带有bash <minecraft
, $0
is bash
)。
如果通过符号链接访问脚本,则脚本将检索该链接的完整路径以及通过 Linux 特定readlink
实用程序扩展的所有符号链接。
名称上的转换将脚本的基本名称替换为config
。也就是说,如果$0
(或readlink $0
视情况而定)是,/path/to/minecraft
则 sed 命令输出/path/to/config
。即使路径不包含任何/
:minecraft
替换为 ,config
它也能工作。
该脚本的要点是查找与该脚本config
在同一目录中调用的文件,并获取该文件(即在与调用脚本相同的上下文中读取并执行该脚本)。config
是一个配置文件,用于定义minecraft
脚本稍后使用的变量。
脚本缺失变量和命令替换用双引号引起来。应该写成
if [ -L "$0" ]
then
source "$(readlink -e "$0" | sed 's:[^/]*$:config:')"
else
source "$(echo "$0" | sed 's:[^/]*$:config:')"
fi
如果脚本的路径带有-
或包含换行符,这仍然会失败,但这种情况很少见。
可以使用 shell 字符串操作结构编写相同的想法(除了对 的外部调用readlink
)。
case $0 in */*) config=$0;; *) config=./$0;; esac # make sure there is a / in $config
if [ -L "$config" ]; then config=$(readlink -e -- "$config"); fi
config=${config%/*}/config