#arrays #bash #random
Вопрос:
У меня есть два каталога с фотографиями, которыми я хочу управлять, чтобы выводить файлы в случайном порядке при каждом запуске сценария. Как бы я создал такой список?
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
Комментарии:
1. Просто
files="$d1 $d2"
2. Хорошо, я надеялся, что будет просто объединить два списка, спасибо. Оттуда, как мне перетасовать этот список файлов, чтобы при повторном просмотре их порядок был рандомизирован?
Ответ №1:
Я бы не стал использовать переменные, если в этом нет необходимости. Это более естественно, если вы свяжете пару команд вместе с трубами или заменой процессов. Таким образом, все работает с потоками данных, не загружая весь список имен в память сразу.
Вы можете использовать shuf
для случайной перестановки входных строк и find
для перечисления файлов по одному на строку. Или, чтобы быть максимально безопасным, давайте использовать
разделители. Наконец, цикл while с подстановкой процесса считывает строку за строкой в переменную.
while IFS= read -d
Тем не менее, если вы хотите использовать некоторые переменные, вам следует использовать массивы. Массивы правильно обрабатывают имена файлов с пробелами и другими специальными символами, в то время как обычные строковые переменные искажают их все.
d1=(/home/Photos/*.jpg)
d2=(/mnt/JillsPC/home/Photos/*.jpg)
files=("${d1[@]}" "${d2[@]}")
Повторять по порядку было бы легко:
for file in "${files[@]}"; do
echo "$file"
done
Однако перетасовка - это сложно. shuf
это по-прежнему лучший инструмент, но он лучше всего работает с потоком данных. Мы можем использовать для печати каждого имени файла с окончанием, которое нам нужно, чтобы сделать счастливым. printf
shuf -z
d1=(/home/Photos/*.jpg)
d2=(/mnt/JillsPC/home/Photos/*.jpg)
files=("${d1[@]}" "${d2[@]}")
while IFS= read -d
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
files=(/home/roy/Photos/*.jpg /mnt/JillsPC/home/jill/Photos/*.jpg)
printf '%sn' "${files[@]}" | sort -R
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
files=(/home/roy/Photos/*.jpg /mnt/JillsPC/home/jill/Photos/*.jpg)
(IFS=
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой ( IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже 'n'
, $'n'
что это правильный способ установить его на разрыв строки). IFS
не требуется при использовании printf
описанного выше метода.
echo ${files[*]}
распечатает все элементы массива сразу, используя IFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок...
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
' -r file; do
echo "$file"
done < <(find /home/Photos/ /mnt/JillsPC/home/Photos/ -name '*.jpg' -print0 | shuf -z)
Тем не менее, если вы хотите использовать некоторые переменные, вам следует использовать массивы. Массивы правильно обрабатывают имена файлов с пробелами и другими специальными символами, в то время как обычные строковые переменные искажают их все.
Повторять по порядку было бы легко:
Однако перетасовка - это сложно. shuf
это по-прежнему лучший инструмент, но он лучше всего работает с потоком данных. Мы можем использовать для печати каждого имени файла с окончанием, которое нам нужно, чтобы сделать счастливым. printf
shuf -z
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок...
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
' -r file; do
echo "$file"
done < <(printf '%s' "${files[@]}" | shuf -z)
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок...
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
' -r file; do
echo "$file"
done < <(find /home/Photos/ /mnt/JillsPC/home/Photos/ -name '*.jpg' -print0 | shuf -z)
Тем не менее, если вы хотите использовать некоторые переменные, вам следует использовать массивы. Массивы правильно обрабатывают имена файлов с пробелами и другими специальными символами, в то время как обычные строковые переменные искажают их все.
Повторять по порядку было бы легко:
Однако перетасовка — это сложно. shuf
это по-прежнему лучший инструмент, но он лучше всего работает с потоком данных. Мы можем использовать для печати каждого имени файла с окончанием, которое нам нужно, чтобы сделать счастливым. printf
shuf -z
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок…
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
n’; echo «${files[*]}») | sort -R
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок…
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
‘ -r file; do
echo «$file»
done < <(find /home/Photos/ /mnt/JillsPC/home/Photos/ -name ‘*.jpg’ -print0 | shuf -z)Тем не менее, если вы хотите использовать некоторые переменные, вам следует использовать массивы. Массивы правильно обрабатывают имена файлов с пробелами и другими специальными символами, в то время как обычные строковые переменные искажают их все.
Повторять по порядку было бы легко:
Однако перетасовка — это сложно. shuf
это по-прежнему лучший инструмент, но он лучше всего работает с потоком данных. Мы можем использовать для печати каждого имени файла с окончанием, которое нам нужно, чтобы сделать счастливым. printf
shuf -z
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок…
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
‘ -r file; do
echo «$file»
done < <(printf ‘%s’ «${files[@]}» | shuf -z)
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок…
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.
‘ -r file; do
echo «$file»
done < <(find /home/Photos/ /mnt/JillsPC/home/Photos/ -name ‘*.jpg’ -print0 | shuf -z)
Тем не менее, если вы хотите использовать некоторые переменные, вам следует использовать массивы. Массивы правильно обрабатывают имена файлов с пробелами и другими специальными символами, в то время как обычные строковые переменные искажают их все.
Повторять по порядку было бы легко:
Однако перетасовка — это сложно. shuf
это по-прежнему лучший инструмент, но он лучше всего работает с потоком данных. Мы можем использовать для печати каждого имени файла с окончанием, которое нам нужно, чтобы сделать счастливым. printf
shuf -z
Дальнейшее чтение:
- Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
- Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
- Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
- Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?
Комментарии:
1. Я нахожу
read -d $'' -r file
,< <()
что за частями и трудно следить , и я действительно не понимаю значения, но я вижу, как чисто это работает. Я экспериментировал с выбора элемента случайным образом из массива, а затем создать временный массив без выбранного элемента, а затем переназначение временного массива обратно в основной массив, а затем повторять, что до тех пор, пока массив был нулевой размер (я предполагаю, что
shuf
что-то подобное в любом случае, выбор элемента в одну сторону, затем продолжается, хотя и гораздо более эффективно, конечно); я получил это работает, но ваш путь-это гений, намного лучше, большое спасибо!2. Я добавил несколько ссылок на соответствующие часто задаваемые вопросы из Вики Грега , которые более подробно объясняют, почему этот код такой тупой. Зачем использовать
while read
(см. №1), почему-print0
и-z
и-d $''
(см. №2), почему< <()
(см. №3).3. Привет, Джон, я придумал другое возможное решение, которое, кажется, работает довольно хорошо; видите ли вы какие-либо недостатки в этом подходе?
Ответ №2:
Я пришел к этому решению после еще некоторого чтения:
Изменить: обновлено с улучшениями Джона из комментариев.
- Вы можете добавить любое количество каталогов в объявление массива (хотя см. предостережение со сложными именами в комментариях).
sort -R
кажется, что он используетсяshuf
внутренне, глядя на егоman
страницу.
Это был оригинал, который работает, но не так надежен, как вышеприведенный:
- При
IFS=$'n'
повторении массива он будет отображаться строка за строкой (IFS=$'somestring'
это синтаксис для строковых литералов с escape-последовательностями. Так непохоже'n'
,$'n'
что это правильный способ установить его на разрыв строки).IFS
не требуется при использованииprintf
описанного выше метода. echo ${files[*]}
распечатает все элементы массива сразу, используяIFS
определенные в
Комментарии:
1. Это будет прекрасно работать на практике. Раз уж вы попросили критику, несколько придирок…
2. Изменение
$IFS
, скорее всего, испортит более поздние команды. Лучше всего поместить его в подоболочку с(IFS=$'n'; echo "${files[@]}") | sort -R
помощью . Или вы можете использоватьprintf '%sn' "${files[@]}"
.3. Файлы по закону могут иметь встроенные новые строки. Это патология, но технически допустимо. Вот почему я прыгал через обручи, чтобы везде использовать разделители NUL. Стоит ли это всех этих хлопот? Я полагаю, это зависит от того, насколько надежным вы хотите, чтобы ваш сценарий был. Если бы я писал что-то для личного пользования, я бы не стал утруждать себя. Но в ответе с переполнением стека, который другие могут скопировать и вставить, я думаю, что стоит показать самую безопасную возможную версию.
4.
${files[*]}
также произойдет сбой, если в файле несколько пробелов подряд; они будут свернуты в один пробел. Вкладки и новые строки также будут преобразованы в пробелы. Уprintf
метода нет такой проблемы.5. Нет необходимости менять
IFS
, если вы используетеprintf '%sn'
.