Составьте список всех файлов в двух папках, затем произвольно повторите просмотр объединенного списка

#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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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. Как я могу прочитать файл (поток данных, переменную) построчно (и/или поле за полем)?
  2. Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?
  3. Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передавать данные для чтения?
  4. Как я могу рандомизировать (перемешать) порядок строк в файле? Или выберите случайную строку из файла, или выберите случайный файл из каталога?

Комментарии:

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' .