`$RANDOM` 在 `find` 的 `-exec` 中不是随机的

`$RANDOM` 在 `find` 的 `-exec` 中不是随机的

我正在尝试在 Linux 机器上查找并移动一大堆文件夹。

所有文件夹的名称都相同,因此我使用echo $RANDOM提供一个随机数来作为文件夹名称。

echo $RANDOM
确实每次运行时都会输出一个随机数。但是,
find . -type d -name .AppleDouble -exec mv \'{}\' \'/raid/data/Storage/AppleDouble/`echo $RANDOM` \;
对每个文件夹使用相同的“随机”数字,因此仅移动一个文件夹。

我认为问题在于开始运行$RANDOM时立即对其进行评估。find如何转义它,以便在选项开始运行$RANDOM之前不计算的值(或者什么是更好的方法来执行此操作)?-exec

注意:我在 busybox 上,所以我无法真正安装任何东西。

答案1

你是对的;您没有引用它,因此在构建find命令行时由 shell 对其进行评估。 不过,通常-exec不使用bash,所以如果你用单引号引用它或转义它,$那么它根本不会被扩展。

bash解决方案是在内部调用-exec

find . -type d -name .AppleDouble -exec bash -c 'echo $RANDOM' \;

答案2

您正在运行的命令存在几个问题。

mv \'{}\' \'/raid/data/Storage/AppleDouble/`echo $RANDOM`

`echo something`相当于something(除非something包含一些特殊字符,在这种情况下附加和命令替换的效果echo通常会使事情变得更糟)。所以这是一种复杂的写作方式

mv \'{}\' \'/raid/data/Storage/AppleDouble/$RANDOM

因此,shell 将三个参数传递给find上面表示的命令行部分的命令:mv'{}''/raid/data/Storage/AppleDouble/12345其中12345是随机值。由于特殊变量的值RANDOM在调用之前由 shell 扩展find,因此执行的所有命令find都将以相同的值运行。另请注意,您有额外的单引号,它们将成为文件名的一部分 - 只需删除它们即可。

由于您想要$RANDOM在每次调用中进行扩展,因此您需要告诉find执行一个将执行的 shell mv,而不是直接find执行mv

find . -type d -name .AppleDouble -exec sh -c 'mv "$0" /raid/data/Storage/AppleDouble/$RANDOM' {} \;

请注意,碰撞概率随机数非常高:$RANDOM最多只能达到 2 15,因此如果您复制的文件超过 213 个,则两个文件复制到同一目标的概率超过 50%。在这种情况下使用随机名称是一个非常糟糕的主意。相反,请使用以下名称保证是独特的对于每个源文件。一种方法是使用源路径的加密哈希:

find . -type d -name .AppleDouble -exec sh -c 'mv "$0" /raid/data/Storage/AppleDouble/$(echo "$0" | md5sum | cut -d " " -f 1)' {} \;

答案3

我不太确定问题到底是什么。

我最终放弃了,并编写了一个外部脚本来传递给finds -exec,这似乎有效。

我不确定为什么我不能把整个命令放在一行中。我使用的 busybox 和 bash 版本似乎有一些奇怪的错误(这是一个老的两者的版本。它是 2006 年发布的 busybox 1.1.0,以及年龄相似的 bash 3.00.16(我找不到 bash 发布历史记录)。

相关内容