Запуск команды для многих файлов

19

У меня есть папка с множеством файлов (xyz1, xyz2, вплоть до xyz5025), и мне нужно запустить скрипт для каждого из них, получив xyz1.faa, xyz2.faa и т. Д. В качестве выходных данных.

Команда для одного файла:

./transeq xyz1 xyz1.faa -table 11

Есть ли способ сделать это автоматически? Может быть, комбо?

Manuel
источник

Ответы:

32
for file in xyz*
do
  ./transeq "$file" "${file}.faa" -table 11
done

Это простой forцикл, который будет перебирать каждый файл, который начинается xyzв текущем каталоге, и вызывать ./transeqпрограмму с именем файла в качестве первого аргумента, именем файла, за которым следует «.faa» в качестве второго аргумента, за которым следует «-table 11» ,

Джефф Шаллер
источник
4
Или, как однострочник for file in xyz*; do ./transeq "$file" "${file}.faa" -table 11; done. Я пишу такие вещи все время. И если вы хотите убедиться, что имена файлов и т. Д. Расширяются так, как вы хотите, просто поставьте echoсразу после doпервого раза, а затем вернитесь в историю оболочки и удалите ее во второй раз.
Дэйв Твид
"$file".faaего немного легче вводить как часть интерактивной однострочной строки, и он безопасен, поскольку .faaне содержит метасимволов оболочки, которые необходимо заключать в кавычки.
Питер Кордес
2
Как примечание, если вы в конечном итоге выполните частичный прогон и захотите перезапустить цикл, xyz*глобус также подберет файлы .faa. Для bash запустите shopt -s extglob( ссылка ), а затем используйте, for file in xyz!(*.faa) ...чтобы исключить файлы .faa от отправки через цикл.
Джефф Шаллер
24

Если вы устанавливаете GNU Parallel, вы можете сделать это параллельно так:

parallel ./transeq {} {}.faa -table 11 ::: xyz*

Если ваша программа интенсивно использует процессор, она должна немного ускориться.

hschou
источник
6

Вы можете сделать что-то вроде этого в bashкомандной строке:

printf '%s\n' {1..5025} | xargs -l -I {} -t ./transeq xyz{} xyz{}.faa -table 11

Мы генерируем целые числа от 1 до 5025, по одной на строку, затем подаем их один за другим в xargs, который инкапсулирует целое число в {}и затем трансплантирует его в командную строку ./transeq соответствующим образом.

Если у вас нет возможности расширения скобок, {n..m}вы можете вызвать seqутилиту для генерации этих чисел.

Или вы всегда можете эмулировать генерацию чисел с помощью:

yes | sed -n =\;5025q | xargs ...

источник
1
Это слишком сложно. for i in {1..5025}; do ./transeq "xyz$i" "xyz$i".faa -table 11; doneэто гораздо проще думать и печатать. Если вы хотите, чтобы он печатал команды перед их выполнением, используйте set -x.
Питер Кордес
Да, это правильно, но то, как ОП сформулировал вопрос, показалось мне, что интерес представляют только файлы с именами xyz1 .. xyz5025. Поэтому я подумал, что если мы сделаем это, используя для xyz *, то нам нужен способ отклонить несоответствующие файлы ... отсюда это. В идеале, если операционная система хочет, чтобы все файлы в каталоге были обработаны, тогда зачем поднимать значение от 1 до 5025? Просто скажите, что я хочу, чтобы все файлы, обработанные в установленном порядке, были бы достаточными.
1
Посмотрите на цикл, который я написал. Он использует for i in {1..5025}для достижения точно такого же результата, как ваш. Вы также можете писать for ((i=1 ; i<=5025 ; i++)); do ./transeq "xyz$i" "xyz$i".faa -table 11; doneна bash, но я обычно использую {a..b}синтаксис диапазона, потому что он быстрее печатается.
Питер Кордес
4

Использование find полезно, когда ваши файлы разбросаны по каталогам

find -name "xyz*" -exec ./transeq {} {}.faa -table 11 \;
Pelle
источник
4

Предполагая, что у вас более одного ядра, и каждый вызов может выполняться независимо от остальных, вы получите значительное ускорение при параллельных запусках.

Относительно простой способ сделать это с помощью -Pпараметра xargs- например, если у вас есть 4 ядра:

echo xyz{1..5025} | \
    xargs -n 1 -P 4 -I{} /path/to/transeq xyz{} xyz{}.faa -table 11

-n 1Говорит , xargsчтобы выбрать только один аргумент из списка для каждого вызова (по умолчанию он будет проходить много) , и -P 4говорит ему , чтобы породить 4 процессов одновременно - когда кто -то умирает, а новая породившие.

ИМХО, вам не нужно устанавливать GNU параллельно для этого простого случая - xargsдостаточно.

ttsiodras
источник
0

Ты можешь использовать xarg

ls | xargs -L 1 -d '\n' your-desired-command

-L 1 вызывает пропуск 1 предмет за раз

-d '\n'сделать вывод из lssplit'ed на основе новой строки.

Аль Мамун
источник