Запуск команди на багатьох файлах


19

У мене є папка з багатьма файлами (xyz1, xyz2, аж до xyz5025), і мені потрібно запустити сценарій на кожному з них, отримуючи xyz1.faa, xyz2.faa тощо, як вихідні дані.

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

./transeq xyz1 xyz1.faa -table 11

Чи є спосіб зробити це автоматично? Може бути комбо для завдань?

Відповіді:


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 через цикл.
Jeff Schaller

24

Якщо ви встановите GNU Parallel, ви можете зробити це паралельно так:

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

Якщо у вас програма є інтенсивним процесором, вона повинна зовсім прискоритися.


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 -name "xyz*" -exec ./transeq {} {}.faa -table 11 \;

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 процесів одночасно - коли хто -то вмирає, а нова породили.

IMHO, вам не потрібно встановлювати паралельно GNU для цього простого випадку - xargsдостатньо.


0

Можна використовувати xarg

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

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

-d '\n'make output of lssplit'ed заснований на новому рядку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.