Uruchomienie polecenia dla wielu plików

19

Mam folder z wieloma plikami (xyz1, xyz2, aż do xyz5025) i muszę uruchomić skrypt na każdym z nich, otrzymując xyz1.faa, xyz2.faa i tak dalej jako dane wyjściowe.

Polecenie dla pojedynczego pliku to:

./transeq xyz1 xyz1.faa -table 11

Czy istnieje sposób, aby to zrobić automatycznie? Może kombinacja for-do?

Manuel
źródło

Odpowiedzi:

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

Jest to prosta forpętla, która będzie iterować po każdym pliku, który zaczyna się xyzw bieżącym katalogu, i ./transeqwywoła program z nazwą pliku jako pierwszym argumentem, a następnie nazwą pliku „.faa” jako drugim argumentem, a następnie „-tabela 11” .

Jeff Schaller
źródło
4
Lub jako jedną wkładką: for file in xyz*; do ./transeq "$file" "${file}.faa" -table 11; done. Cały czas piszę takie rzeczy. A jeśli chcesz sprawdzić, czy nazwy plików itp. Są rozwijane tak, jak chcesz, po prostu echopo doraz pierwszy umieść poprawkę, a następnie wróć do historii powłoki i usuń ją po raz drugi.
Dave Tweed
"$file".faajest nieco łatwiejszy do wpisania jako część interaktywnej jednowierszowej i jest bezpieczny, ponieważ .faanie zawiera żadnych metaznaków powłoki, które należy cytować.
Peter Cordes
2
Uwaga: jeśli zakończysz częściowe uruchomienie i chcesz zrestartować pętlę, xyz*glob również pobierze pliki .faa. Aby uruchomić bash, uruchom shopt -s extglob( odwołanie ), a następnie użyj, for file in xyz!(*.faa) ...aby wykluczyć wysyłanie plików .faa przez pętlę.
Jeff Schaller
24

Jeśli zainstalujesz GNU Parallel , możesz to zrobić równolegle w następujący sposób:

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

Jeśli program intensywnie wykorzystuje procesor, powinien znacznie przyspieszyć.

hschou
źródło
6

Możesz zrobić coś takiego w bashwierszu poleceń:

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

Generujemy liczby całkowite od 1 do 5025, jeden / wiersz, a następnie podajemy je jeden po drugim do xargs, który hermetyzuje liczbę całkowitą do, {}a następnie transplantuje ją do wiersza poleceń ./transeq w odpowiedni sposób.

Jeśli nie masz funkcji rozwijania nawiasów klamrowych, {n..m}możesz wywołać seqnarzędzie do wygenerowania tych liczb.

Lub zawsze możesz emulować generowanie liczb za pomocą:

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

źródło
1
To jest zbyt skomplikowane. for i in {1..5025}; do ./transeq "xyz$i" "xyz$i".faa -table 11; donejest o wiele łatwiejsze do myślenia i pisania. Jeśli chcesz, aby drukował polecenia przed ich wykonaniem, użyj set -x.
Peter Cordes
Tak, zgadza się, ale sposób, w jaki OP sformułował pytanie, wydawał mi się interesujący tylko pliki o nazwach xyz1 .. xyz5025. Pomyślałem więc, że jeśli zrobimy to za pomocą xyz *, potrzebujemy sposobu na odrzucenie plików niezgodnych ... stąd to. Idealnie, jeśli OP chce przetworzyć wszystkie pliki w katalogu, to po co zwiększać liczbę od 1 do 5025? Wystarczy powiedzieć, że chcę, aby wszystkie pliki przetwarzane w określony sposób byłyby wystarczające.
1
Spójrz na napisaną przeze mnie pętlę. Pozwala for i in {1..5025}osiągnąć dokładnie taki sam wynik jak twój. Możesz także pisać for ((i=1 ; i<=5025 ; i++)); do ./transeq "xyz$i" "xyz$i".faa -table 11; donebash, ale zwykle używam {a..b}składni zakresu, ponieważ szybciej jest pisać.
Peter Cordes
4

Za pomocą funkcji znajdź przydatnej, gdy pliki są rozproszone w katalogach

find -name "xyz*" -exec ./transeq {} {}.faa -table 11 \;
Pelle
źródło
4

Zakładając, że masz więcej niż jeden rdzeń i każde wywołanie może działać niezależnie od reszty, zyskasz całkiem przyspieszenie dzięki równoległym biegom.

Względnie prosty sposób to zrobić za pomocą -Pparametru xargs- na przykład, jeśli masz 4 rdzenie:

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

-n 1Mówi xargswybrać tylko jeden argument z listy dla każdej inwokacji (domyślnie byłoby przekazać mnóstwo) , a -P 4mówi się na tarło 4 procesów w tym samym czasie - gdy ktoś umiera, jest nowy zrodził.

IMHO, nie musisz instalować GNU równolegle dla tej prostej skrzynki - xargswystarczy.

ttsiodras
źródło
0

Możesz użyć xarg

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

-L 1 powoduje przejście 1 przedmiotu na raz

-d '\n'make wyjście lsjest podzielone na podstawie nowej linii.

Al Mamun
źródło