Contents

在bash中展开相对路径

1.概述

在本教程中,我们将了解在 bash 中扩展相对路径的各种方法。

2. 绝对路径和相对路径的区别

在 Linux 中,路径用于引用目录或文件。我们指定从文件系统的根到最终目的地的完整路径,使用第一个斜杠 ( / ) 作为根,后面的斜杠作为分隔符

/etc/ssl/certs
/usr/bin/ls
/usr/lib/libssl.so.3 

**但是,对于相对路径,我们以文件或目录名称而不是斜杠开始路径。**这意味着它们是相对于当前目录的:

file.txt
./file.txt
../../usr/bin/ls

让我们通过一个例子更清楚地理解这一点。假设我们在目录*/tmp/files中,我们在其中创建了一个名为file1的文件。现在,我们可以在该特定目录中使用路径file1./file1*访问该文件,但不能从其他任何地方访问:

$ cd /tmp/files/
$ touch file1
$ ls ./file1
./file1
$ cd /tmp/
$ ls ./file1
ls: ./file1: No such file or directory

由于我们使用的是相对路径,因此我们无法从其他目录访问该文件。因此,我们可以从任何地方通过绝对路径访问文件,而相对路径取决于当前目录。

我们使用单点和双点 分别表示当前目录和父目录。**我们可以使用多个双点来继续向上的目录结构。*假设我们要创建从主目录到/etc/passwd*文件的相对路径:

$ pwd
/home/blogdemo
$ cat ../../etc/passwd
root:x:0:0:root:/root:/bin/sh
...

通过两个双点,我们到达*//home/blogdemo。*

3. 解析相对路径

我们可能需要在各种情况下解析相对路径,例如将它们传递给需要绝对路径的程序。

3.1.使用 Bash 内置函数

我们可以创建一个 bash 函数,该函数利用基本的 bash 内置函数(如pwd和变量替换)来实现我们的目的。这避免了调用外部进程的开销:

resolve_relative_path() (
    # If the path is a directory, we just need to 'cd' into it and print the new path.
    if [ -d "$1" ]; then
        cd "$1" || return 1
        pwd
    # If the path points to anything else, like a file or FIFO
    elif [ -e "$1" ]; then
        # Strip '/file' from '/dir/file'
        # We only change the directory if the name doesn't match for the cases where
        # we were passed something like 'file' without './'
        if [ ! "${1%/*}" = "$1" ]; then
            cd "${1%/*}" || return 1
        fi
        # Strip all leading slashes upto the filename
        echo "$(pwd)/${1##*/}"
    else
        return 1 # Failure, neither file nor directory exists.
    fi
)

我们必须将函数包裹在方括号而不是花括号中,以便它在子 shell 中运行并在退出时恢复原始工作目录。

请注意pwd默认不解析符号链接,所以如果我们在*/tmp/symlinked_dir中,它是/tmp/original_dir的符号链接,那么pwd将只打印/tmp/symlinked_dir*。我们可以使用*-P*标志来解析目录符号链接。但是,此函数仍无法解析文件符号链接。

让我们用几个参数来测试这个函数:

$ pwd
/tmp/test
$ ls
directory  file1
$ resolve_relative_path file1
/tmp/test/file1
$ resolve_relative_path ..
/tmp
$ resolve_relative_path ../test/directory
/tmp/test/directory
$ resolve_relative_path /usr/lib/../bin/..
/usr

我们可以使用readlink 命令来解析相对路径,包括符号链接。它使用-f*标志打印完整路径*:

$ readlink -f /usr/../tmp/link
/tmp/real

这里 /tmp/link/tmp/real文件的符号链接。

readlink -f仅在使用不存在的目录调用它时返回非零退出代码,但如果文件的目录存在则返回零。因此,readlink -f /tmp/non-existent将返回 0,但readlink -f /non-existent-dir/non-existent-file将返回 1

3.3. 使用realpath

最后,我们有realpath 命令,其行为类似于readlink -f

$ realpath /tmp/non-existent; echo $?
/tmp/non-existent
0
$ realpath /non-existent-dir/non-existent-file; echo $?
realpath: /non-existent-dir: No such file or directory
1
$ realpath /tmp/link
/tmp/real