我有一个bash脚本,它使用像
这样的循环处理目录中的所有文件表示我在* .txt中 做 OPS ..... 完成
有数千个文件,由于'* .txt'扩展,它们总是以字母数字顺序处理。
是否有一种简单的方法来随机排序并仍然确保我只处理所有文件一次?
答案 0 :(得分:3)
您可以通过sort命令管道文件名:
ls | sort --random-sort | xargs ....
答案 1 :(得分:3)
假设文件名没有空格,只需替换List::Util::shuffle的输出。
for i in `perl -MList::Util=shuffle -e'$,=$";print shuffle<*.txt>'`; do
....
done
如果文件名确实有空格但没有嵌入换行符或反斜杠,请一次读一行。
perl -MList::Util=shuffle -le'$,=$\;print shuffle<*.txt>' | while read i; do
....
done
要在Bash中完全安全,请使用以NUL结尾的字符串。
perl -MList::Util=shuffle -0 -le'$,=$\;print shuffle<*.txt>' |
while read -r -d '' i; do
....
done
效率不高,但如果需要,可以在纯Bash中执行此操作。 sort -R
在内部做了类似的事情。
declare -a a # create an integer-indexed associative array
for i in *.txt; do
j=$RANDOM # find an unused slot
while [[ -n ${a[$j]} ]]; do
j=$RANDOM
done
a[$j]=$i # fill that slot
done
for i in "${a[@]}"; do # iterate in index order (which is random)
....
done
或使用传统的Fisher-Yates shuffle。
a=(*.txt)
for ((i=${#a[*]}; i>1; i--)); do
j=$[RANDOM%i]
tmp=${a[$j]}
a[$j]=${a[$[i-1]]}
a[$[i-1]]=$tmp
done
for i in "${a[@]}"; do
....
done
答案 2 :(得分:1)
这是一个答案,它依赖于awk
中的非常基本的功能,所以它应该在unices之间移植。
ls -1 | awk '{print rand()*100, $0}' | sort -n | awk '{print $2}'
编辑:
eppeient提出了一个很好的观点,即上述不是空间安全的。这是一个版本:ls -1 | awk '{print rand()*100, $0}' | sort -n | sed 's/[0-9\.]* //'
答案 3 :(得分:1)
以下是使用标准unix命令的解决方案:
for i in $(ls); do echo $RANDOM-$i; done | sort | cut -d- -f 2-
答案 4 :(得分:1)
如果你有GNU coreutils,你可以使用shuf
:
while read -d '' f
do
# some stuff with $f
done < <(shuf -ze *)
这适用于名称中带有空格或换行符的文件。
偏离主题的修改:
在评论中说明 SiegeX的点:
$ a=42; echo "Don't Panic" | while read line; do echo $line; echo $a; a=0; echo $a; done; echo $a
Don't Panic
42
0
42
$ a=42; while read line; do echo $line; echo $a; a=0; echo $a; done < <(echo "Don't Panic"); echo $a
Don't Panic
42
0
0
管道导致while
在子shell中执行,因此子项中变量的更改不会回流到父项。
答案 5 :(得分:0)
这是一个Python解决方案,如果它在您的系统上可用
import glob
import random
files = glob.glob("*.txt")
if files:
for file in random.shuffle(files):
print file