Допустим, у меня есть файл list_of_files.txt
, в котором каждая строка соответствует файлу на диске. Например:
dir1/fileA.ext1
dir1/subdir1/fileB.ext2
fileC.ext3
dir2/fileD.ext4
fileE.ext5
Я хочу случайным образом выбрать несколько файлов из этого списка и вычислить для них cksum
или .md5sum
Я знаю, что могу случайным образом выбрать, скажем, 3 файла с помощью shuf -n 3 list_of_files.txt
, но как мне заставить cksum
их обрабатывать их как имена файлов, а не как текстовое содержимое?
решение1
Если пути в файле завершаются символом новой строки и предоставляются «как есть», т. е. если каждая строка представляет собой отдельный дословный путь, то подойдет цикл оболочки:
shuf -n 3 list_of_files.txt | while IFS= read -r pth; do
cksum "$pth"
done
Также есть xargs
(см.Спецификация POSIXи более продвинутыеГНУxargs
), естьГНУparallel
(примечаниеparallel
существует не-GNUи я не имею в виду это). С правильным инструментом и соответствующими параметрами вы можете сделать так, чтобы один cksum
процесс выполнялся на нескольких путях ( cksum
в целом, создание меньшего количества процессов выгодно) или запустить два или более cksum
процессов параллельно.
Чтобы обработать всего три файла, я могу придерживаться нашего цикла оболочки из-за переносимости; если только файлы не большие и я не ожидаю, что три cksum
процесса, запущенных параллельно, будут значительно быстрее, чем один cksum
за раз. Я не эксперт в GNU parallel
, но, кажется, решение такое же простое, как:
shuf -n 3 list_of_files.txt | parallel cksum
По умолчанию GNU parallel
ограничивает количество одновременных заданий числом ядер ЦП. В настоящее время распространены три или более ядер, поэтому команда, вероятно, запустит три cksum
процесса параллельно. Формально это непереносимо. Также обратите внимание, что параллельная обработка трех файлов означает параллельное чтение трех файлов. Ввод-вывод может быть узким местом, и это может снизить преимущество параллельных заданий или даже ухудшить ситуацию.
Даже тогда это parallel
может быть полезно. Используйте, -j 1
чтобы ограничить количество заданий до 1:
shuf -n 3 list_of_files.txt | parallel -j 1 cksum
Файлы будут обрабатываться последовательно, как в нашем цикле оболочки, но синтаксис проще. В случае нашего цикла оболочки вам нужно знать, что вы хотитеIFS= read -r pth
, а не просто read pth
; и вам нужно знать, что вы (во многих оболочках) хотитеcksum "$pth"
, а не cksum $pth
. Решение с GNU parallel
менее подвержено ошибкам.ЦЕЛОВАТЬ.
Примечание xargs
по умолчанию интерпретирует кавычки и обратные косые черты, а пробелы считает разделителями. Это означает, shuf -n 3 list_of_files.txt | xargs cksum
что это, вероятно, не то, что вам нужно. Ваш пример будет работать, но в целом вам нужны дополнительные кавычки и/или обратные косые черты в файле; xor вам нужен xargs -d '\n'
where -d
— непереносимая опция GNU xargs
. Я предполагал, что «пути в файле завершаются символом новой строки и предоставляются как есть». С этим предположением GNU parallel
работает «из коробки» (т. е. без дополнительных опций), xargs — нет. С GNU xargs
вы можете сделать это:
shuf -n 3 list_of_files.txt | xargs -d '\n' cksum
Если вы можете использовать GNU xargs
(чтобы спасти положение с помощью -d '\n'
), то, вероятно, вы можете использовать GNU parallel
. Если вы забудете -j 1
при использовании GNU parallel
, команда может работать хуже, но она все равно будет работать. Если вы забудете -d '\n'
при использовании GNU xargs
и пути будут предоставлены как есть, то это ошибка. Вот почему я рекомендовал GNU parallel
в первую очередь.
GNU parallel способен обрабатывать строки с нулевым завершением (опция -0
), как и GNU xargs
( -0
вместо -d '\n'
) и GNU shuf
(с -z
). Ваш входной файл использует строки с символом новой строки, но если вам когда-либо понадобится работать с путями, которые (могут) содержать символы новой строки, то изменение символа завершения в файле и добавление соответствующих параметров — это выход.