如何为所有子目录中的每个文件创建符号链接?

如何为所有子目录中的每个文件创建符号链接?

我有以下文件夹/文件的结构,例如

./3DO Company, The - 3DO/goldstar.bin
./3DO Company, The - 3DO/panafz10e-anvil.bin
./Arcade/pgm.zip
./Arcade/skns.zip
./Atari - 400-800/ATARIBAS.ROM
./Atari - 5200/5200.rom
./Atari - 7800/7800 BIOS (E).rom
./Atari - Lynx/lynxboot.img
./Coleco - ColecoVision/coleco.rom

这只是为了按星号排列文件夹/文件,但我需要所有子文件夹上每个文件的符号链接(不是复制,只是我没有足够的可用空间来制作副本)但我需要文件的全名包括特殊字符并且只使用相对路径,而不是绝对路径。

嗯,我知道使用循环,比如“for”是可能的,我有这个想法,但是在 GNU/Linux 中的 bash 下我没有正确的命令来执行此操作。

我搜索的结果是:

./goldstar.bin
./panafz10e-anvil.bin
./pgm.zip
./skns.zip
./ATARIBAS.ROM
./5200.rom
./7800 BIOS (E).rom
./lynxboot.img
./coleco.rom

有人可以帮我吗?

答案1

有了find,基本解决方案:

# remember to cd to the right directory first
find . -exec ln -s {} ./ \;

注意事项:

  • 基本解决方案将尝试创建指向所有文件,包括目录类型的文件;您可能只想要常规文件的链接,所以这-type f是一个好主意。

  • 尝试直接链接到位于其下方的文件.和其.自身将会失败(file exists),因为路径已被占用(边缘情况:如果在find发现之后但在ln执行操作之前删除了该文件,则会创建指向其自身的符号链接;比较托克托)。 和GNUfind -mindepth 2允许您跳过这些文件;正确答案(可移植地)您可以检查路径中是否至少有两个斜线:-path './*/*'

改进后的命令为:

find . -type f -path './*/*' -exec ln -s {} ./ \;

这仍然不是最优的,因为该命令ln为每个匹配的文件运行单独的命令。如果您的ln支持-t,那么-exec ln -s -t ./ {} +它将起作用。便携改进是:

find . -type f -path './*/*' -exec sh -c 'ln -s "$@" ./' find-sh {} +

重点是-exec … {} +可以一次处理多个路径名,但{}必须就在之前+,所以-exec ln -s {} ./ +行不通。在 shell 代码中$@可以位于任何地方。通过使用 shell,我们可以使一个可移植程序ls处理传递的多个路径名findfind-sh解释如下:中的第二个 sh 是什么sh -c 'some shell code' sh

如果要创建符号链接并且名称已经在当前工作目录中被使用,那么将不会创建链接并且不会覆盖现有文件。

“已被占用”可能指的是之前创建的符号链接。这意味着,如果有同名的常规文件(显然在不同的目录中),则最多会创建一个同名的符号链接(可能会出现file exists错误)。符号链接的目标将是该组中的第一个文件。一般来说,你无法轻易预测顺序(我认为任何(?)find都使用目录顺序,递归地),因此您无法轻易猜出将链接到哪一个同名文件。

要观察正在处理的内容,请-print在最后添加(ln -v这是一种替代方法,但不可移植)。最后的可移植命令是:

find . -type f -path './*/*' -exec sh -c 'ln -s "$@" ./' find-sh {} + -print

注意-exec … {} +总是被评估为真,它所做的不会影响-print。如果-print打印某个路径名,这仅表示尝试创建符号链接;这并不意味着尝试成功。如果您只想打印成功链接的路径名,则需要-exec ln -s {} ./ \; -print。这将起作用,因为-exec … \;根据内部命令的退出状态 评估 为真或假,因此如果ln失败则-print不会打印路径名。

相关内容