![`$RANDOM` 在 `find` 的 `-exec` 中不是随机的](https://linux22.com/image/22623/%60%24RANDOM%60%20%E5%9C%A8%20%60find%60%20%E7%9A%84%20%60-exec%60%20%E4%B8%AD%E4%B8%8D%E6%98%AF%E9%9A%8F%E6%9C%BA%E7%9A%84.png)
我正在尝试在 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
我不太确定问题到底是什么。
我最终放弃了,并编写了一个外部脚本来传递给find
s -exec
,这似乎有效。
我不确定为什么我不能把整个命令放在一行中。我使用的 busybox 和 bash 版本似乎有一些奇怪的错误(这是一个老的两者的版本。它是 2006 年发布的 busybox 1.1.0,以及年龄相似的 bash 3.00.16(我找不到 bash 发布历史记录)。