在 bash 个脚本中发出 pushd 命令后 readlink 命令行为异常

readlink command misbehave after issueing pushd command in bash scripts

我遇到了一个复杂的问题,我试着用下面的简单例子来解释它

在我的系统中我有

ubuntu@ubuntu:~/temp$ pwd
/home/ubuntu/temp
ubuntu@ubuntu:~/temp$ ls
temp1  test.sh
ubuntu@ubuntu:~/temp$ 

在temp.sh我有

#!/bin/bash

echo "Arg 0 = [=12=]"
echo "Arg 1 = "
echo "Arg 0 Full Path $(readlink -f [=12=])"
echo "Arg 1 Full Path $(readlink -f )"
pushd /var/log
echo "Arg 0 = [=12=]"
echo "Arg 1 = "
echo "Arg 0 Full Path $(readlink -f [=12=])"
echo "Arg 1 Full Path $(readlink -f )"

现在我运行在下面的路

ubuntu@ubuntu:~/temp$ ./test.sh temp1
Arg 0 = ./test.sh
Arg 1 = temp1
Arg 0 Full Path /home/ubuntu/temp/test.sh
Arg 1 Full Path /home/ubuntu/temp/temp1
/var/log ~/temp
Arg 0 = ./test.sh
Arg 1 = temp1
Arg 0 Full Path /var/log/test.sh
Arg 1 Full Path /var/log/temp1

在这里您可以看到 readlink 在发出 pushd 命令后显示了错误的 Arg0 和 Arg1 文件路径。 如果我删除 popd 命令,那么它打印正常。

那么为什么这里 readlink 行为不端?

readlink 在这里的行为是正确的,这里唯一需要理解的是 pushd 的行为。 pushd 是改变当前目录堆栈的命令。看下图就明白了。

最初 test.sh 有一些完整路径,在 运行 宁 pushd 一个目录后,即 (/var/log) 被插入到目录堆栈中。 堆栈的最左边目录(或最顶层目录)成为当前目录。 如果你 运行 popd ,这意味着堆栈从顶部开始变空。只要你在 popd 之后再次 运行 readlink -f test.sh ,你就会有初始目录。在你的情况下它将是 /home/ubuntu/temp/test.sh

给定相对路径,readlink 将相对于进程工作目录解释它们,并输出绝对路径(解析中间的符号链接)。

这里的关键点是进程工作目录(又名当前目录)。

所以如果/tmp是当前目录(假设没有符号链接),readlink ./path/to/file将输出/tmp/path/to/file

您正在使用的另一个命令,pushd 将更改进程工作目录。

所以顺序

readlink ./path/to/file
pushd /some/other/place
readlink ./path/to/file

两者 readlink 都可能解析为两个不同的绝对路径。

这里没有不当行为。完全由设计决定。