Рандомизация порядка arg для bash для оператора - PullRequest
0 голосов
/ 16 декабря 2009

У меня есть скрипт bash, который обрабатывает все файлы в каталоге, используя цикл, подобный

для меня в * .txt делать опс ..... сделано

Существуют тысячи файлов, и они всегда обрабатываются в алфавитно-цифровом порядке из-за расширения * .txt.

Есть ли простой способ рандомизировать порядок и при этом гарантировать, что я обработаю все файлы только один раз?

Ответы [ 6 ]

3 голосов
/ 16 декабря 2009

Предполагая, что имена файлов не имеют пробелов, просто подставьте вывод 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

Или используйте традиционную тасовку Фишера-Йейтса.

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
3 голосов
/ 16 декабря 2009

Вы можете передать имена файлов через команду сортировки:

ls | sort --random-sort | xargs ....
1 голос
/ 17 декабря 2009

Если у вас есть GNU coreutils, вы можете использовать shuf:

while read -d '' f
do
    # some stuff with $f
done < <(shuf -ze *)

Это будет работать с файлами с пробелами или символами новой строки в их именах.

Не по теме Редактировать:

Для иллюстрации SiegeX's пункт в комментарии:

$ 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 выполняется в подоболочке, и поэтому изменения переменных в дочернем элементе не возвращаются к родительскому элементу.

1 голос
/ 16 декабря 2009

Вот решение со стандартными командами Unix:

for i in $(ls); do echo $RANDOM-$i; done | sort | cut -d- -f 2-
1 голос
/ 16 декабря 2009

Вот ответ, основанный на базовых функциях awk, поэтому он должен быть переносимым между юнитами.

ls -1 | awk '{print rand()*100, $0}' | sort -n | awk '{print $2}'

EDIT:

ephemient подчеркивает, что вышесказанное небезопасно. Вот версия, которая:

ls -1 | awk '{print rand()*100, $0}' | sort -n | sed 's/[0-9\.]* //'
0 голосов
/ 17 декабря 2009

Вот решение Python, если оно доступно в вашей системе

import glob
import random
files = glob.glob("*.txt")
if files:
    for file in random.shuffle(files):
        print file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...