首页 > 解决方案 > 列出两个文件夹中的所有文件,然后随机遍历组合列表

问题描述

我有两个包含照片的目录,我想在每次运行脚本时对其进行操作以输出文件的随机顺序。我将如何创建这样的列表?

d1=/home/Photos/*.jpg
d2=/mnt/JillsPC/home/Photos/*.jpg

# somehow make a combined list, files = d1 + d2
# somehow randomise the file order
# during execution of the for;do;done loop, no file should be repeated

for f in $files; do
    echo $f   # full path to each file
done

标签: arraysbashrandom

解决方案


如果你不需要,我不会使用变量。如果将几个命令与管道或进程替换链接在一起会更自然。这样一来,一切都在数据流上运行,而无需一次将整个名称列表加载到内存中。

您可以使用shuf随机排列输入行,并find每行列出一个文件。或者,为了最大程度地安全,让我们使用\0分隔符。最后,带有进程替换的 while 循环将逐行读取到变量中。

while IFS= read -d $'\0' -r file; do
    echo "$file"
done < <(find /home/Photos/ /mnt/JillsPC/home/Photos/ -name '*.jpg' -print0 | shuf -z)

也就是说,如果您确实想使用一些变量,那么您应该使用数组。数组正确处理带有空格和其他特殊字符的文件名,而常规字符串变量将它们全部搞砸。

d1=(/home/Photos/*.jpg)
d2=(/mnt/JillsPC/home/Photos/*.jpg)
files=("${d1[@]}" "${d2[@]}")

按顺序迭代很容易:

for file in "${files[@]}"; do
    echo "$file"
done

洗牌虽然很棘手。shuf仍然是最好的工具,但它在数据流上效果最好。我们可以用来打印每个文件名,并带有我们需要使快乐printf的尾随。\0shuf -z

d1=(/home/Photos/*.jpg)
d2=(/mnt/JillsPC/home/Photos/*.jpg)
files=("${d1[@]}" "${d2[@]}")

while IFS= read -d $'\0' -r file; do
    echo "$file"
done < <(printf '%s\0' "${files[@]}" | shuf -z)

进一步阅读:

  1. 如何逐行(和/或逐字段)读取文件(数据流、变量)?
  2. 如何找到并安全地处理包含换行符、空格或两者的文件名?
  3. 我在管道中的循环中设置变量。为什么它们在循环终止后消失?或者,为什么我不能通过管道读取数据?
  4. 如何随机化(打乱)文件中的行顺序?或者从文件中随机选择一行,或者从目录中随机选择一个文件?

推荐阅读