子目录中的符号链接别名文件而不更改当前目录

子目录中的符号链接别名文件而不更改当前目录

似乎将一个文件符号链接到子目录中的新文件应该很简单......而无需移动子目录。但有关语法的某些内容令人困惑并且与我的预期相反。这是一个测试用例:

mkdir temp
cd temp
mkdir deploy
echo "Contents of the build file!" > deploy/resources.build.php
ln -s deploy/resources.build.php deploy/resources.php
cat deploy/resources.php #bad symlink

这只会创建一个损坏的符号链接!我在构建环境设置脚本中运行它,所以我想尽可能避免更改当前工作目录。

ln -s deploy/resources.build.php resources.php
cat deploy/resources.php

也不起作用,因为它在临时目录而不是部署子目录中创建符号链接。

cd deploy
ln -s resources.build.php resources.php
cd ..

这可行,但我更想知道如何在不更改目录的情况下做到这一点。

使用完整路径,例如:

/home/whatever/src/project/temp/stuff/temp/deploy/resources.build.php

可行,但不方便且有些不切实际,特别是在构建环境中,所有项目内容在构建之间可能有所不同,等等。

如何在子目录中的两个文件之间创建符号链接,而不移入该子目录并移出该子目录,同时为新文件“别名”指定一个新名称?

答案1

但有关语法的某些内容令人困惑并且与我的预期相反。

ln以您使用的形式表示的参数是:

ln [选项]... [-T] TARGET LINK_NAME(第一种形式)

令人困惑且不直观的是,当您创建符号链接时,目标for 的参数ln预计不是文件的路径,而是要创建的符号链接的内容。如果你想一想,很明显事情一定是这样的。考虑:

$ echo foo >foo
$ ln -s foo bar1
$ ln -s $PWD/foo bar2
$ cat bar1
foo
$ cat bar2
foo
$ ls -l bar1 bar2
lrwxrwxrwx 1 matt matt  3 Dec 29 16:29 bar1 -> foo
lrwxrwxrwx 1 matt matt 29 Dec 29 16:29 bar2 -> /home/matt/testdir/foo

在该示例中,我创建了 2 个符号链接,名为“bar1”和“bar2”,它们指向同一个文件。 ls表明符号链接本身具有不同的内容 - 一个包含绝对路径,一个包含相对路径。因此,即使移动到另一个目录,一个也会继续工作,而另一个则不会:

$ mv bar2 /tmp
$ cat /tmp/bar2
foo
$ mv bar1 /tmp
$ cat /tmp/bar1
cat: /tmp/bar1: No such file or directory

因此,考虑到我们必须能够创建相对和绝对符号链接,甚至创建损坏的符号链接,如果稍后创建目标文件,这些符号链接将变得未损坏,目标参数必须解释为自由格式文本,而不是已存在文件的路径。

如果您想创建一个名为deploy/resources.php的文件,该文件链接到deploy/resources.build.php,您需要决定是否要创建一个绝对符号链接(它对移动的符号链接具有弹性,但如果目标被移动),或相对符号链接(只要符号链接和目标一起移动并保持相同的相对路径,它将继续工作)。

要创建绝对符号链接,您可以这样做:

$ ln -s $PWD/deploy/resources.build.php deploy/resources.php

要创建相对路径,您首先要找出从源到目标的相对路径。在这种情况下,由于源和目标彼此位于同一目录中,因此您可以执行以下操作:

$ ln -s resources.build.php deploy/resources.php

如果它们不在同一目录中,您需要执行以下操作:

$ ln -s ../foo/f bar/b

在这种情况下,即使 和foobar在当前目录中,您也需要将 a 包含../ln 目标因为它描述了如何f从包含b.

ln这是一个非常长的解释,但希望它可以帮助您更好地理解语法。

答案2

您可以在子 shell 中创建链接,如下所示:

  (cd deploy && ln -s resources.build.php resources.php && cat resources.php)

当子 shell 结束执行时,您会发现自己仍在正确的目录中。

或者,您可以尝试

 ln -s resources.build.php deploy/resources.php

这也有效,忽略了在 CL 中包含该文件的事实资源.build.php不在您发出命令的目录中,但实际上在里面。/部署

答案3

这让我很困惑,直到我意识到符号链接基本上是一个配置文件。即我如何将该路径数据写入一个简单的文本文件:

ln -s [target] [link name]

变成:

echo [target] > [link name]

我(可能还有OP)所犯的错误在于思考需要了解其目标文件。不在乎。它只是将一些路径信息写入文件中。这是一个完全合理的命令:

ln -s /path/doesnt/exist/file.err
ll
file.err -> /path/doesnt/exist/file.err

因此:

ln -s deploy/resources.build.php deploy/resources.php

resources.php生成一个在引用该文件夹中./deploy文件的文件resources.build.php夹中调用的 simlink 文件./deploy/deploy/

这不太可能是您想要的,并且会给出一个错误的(损坏的)链接。该链接没有任何问题,如果您将该文件放在那里,那么该链接就可以工作。然而,(正如其他人指出的)我和OP想要的是:

ln -s resources.build.php deploy/resources.php

答案4

我最近遇到了这个问题。请记住,这sourcetarget.

❯ ln -s source target

这就是为什么您可能需要在源中使用绝对路径或将当前目录更改为最终目标目录,以使源(AKA descriptor)具有其显示的意义。

示例:将源链接a到目标b

root
  ├── foo
  │    └── a
  └── bar
❯ pwd
root
❯ ln -s ../foo/a ./bar/b

在此示例中,文件的描述b../foo/a。所以,由于我是文件b,我应该:

  1. 从 向上一级目录bar
  2. 改成foo
  3. 寻找a
root
  ├── foo
  │    └── a
  └── bar
       └── b -> ../foo/a

相关内容