Menjalankan perintah pada banyak file

19

Saya punya folder dengan banyak file (xyz1, xyz2, hingga xyz5025) dan saya perlu menjalankan skrip pada setiap file, mendapatkan xyz1.faa, xyz2.faa, dan seterusnya sebagai output.

Perintah untuk satu file adalah:

./transeq xyz1 xyz1.faa -table 11

Apakah ada cara untuk melakukan itu secara otomatis? Mungkin kombo yang harus dikerjakan?

Manuel
sumber

Jawaban:

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

Ini adalah forloop sederhana yang akan mengulangi setiap file yang dimulai dengan xyzdi direktori saat ini dan memanggil ./transeqprogram dengan nama file sebagai argumen pertama, nama file diikuti oleh ".faa" sebagai argumen kedua, diikuti oleh "-tabel 11" .

Jeff Schaller
sumber
4
Atau, sebagai satu-kapal: for file in xyz*; do ./transeq "$file" "${file}.faa" -table 11; done. Saya mengetik hal semacam ini sepanjang waktu. Dan jika Anda ingin memverifikasi bahwa nama file, dll. Diperluas dengan cara yang Anda inginkan, cukup beri echohak setelah doyang pertama kali, lalu kembali ke riwayat shell Anda dan hapus itu untuk yang kedua kalinya.
Dave Tweed
"$file".faasedikit lebih mudah diketik sebagai bagian dari one-liner interaktif, dan aman karena .faatidak mengandung karakter meta shell yang perlu dikutip.
Peter Cordes
2
Sebagai catatan, jika Anda berakhir dengan menjalankan sebagian dan ingin memulai ulang loop, xyz*glob akan mengambil file .faa juga. Untuk bash, jalankan shopt -s extglob( referensi ), lalu gunakan for file in xyz!(*.faa) ...untuk mengecualikan file .faa agar tidak dikirim melalui loop.
Jeff Schaller
24

Jika Anda menginstal GNU Parallel Anda dapat melakukannya secara paralel seperti ini:

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

Jika program Anda menggunakan CPU intensif, kecepatannya harus sedikit.

hschou
sumber
6

Anda dapat melakukan sesuatu seperti ini di bashbaris perintah:

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

Kami membuat bilangan bulat dari 1 hingga 5025, satu / baris, kemudian mengumpankannya satu per satu ke xargs, yang merangkum bilangan bulat ke dalam {}dan kemudian mentransplantasikannya ke dalam baris perintah ./transeq dengan cara yang sesuai.

Jika Anda tidak memiliki fasilitas brace-ekspansi {n..m}maka Anda dapat meminta sequtilitas untuk menghasilkan angka-angka itu.

Atau, Anda selalu dapat meniru generasi numerik melalui:

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

sumber
1
Itu terlalu rumit. for i in {1..5025}; do ./transeq "xyz$i" "xyz$i".faa -table 11; doneadalah cara yang lebih mudah untuk dipikirkan dan diketik. Jika Anda ingin mencetak perintah sebelum menjalankannya, gunakan set -x.
Peter Cordes
Ya itu benar, tetapi cara OP merumuskan pertanyaan bagi saya bahwa hanya file dengan nama xyz1 .. xyz5025 yang menarik. Jadi saya pikir jika kita melakukannya menggunakan xyz * maka kita perlu cara untuk menolak file yang tidak sesuai ... maka ini. Idealnya jika OP ingin semua file dalam direktori diproses, lalu mengapa membawa the1 to 5025? Katakan saja saya ingin semua file diproses dengan cara yang ditentukan sudah cukup.
1
Lihatlah loop yang saya tulis. Ini digunakan for i in {1..5025}untuk mencapai hasil yang persis sama dengan milik Anda. Anda juga bisa menulis for ((i=1 ; i<=5025 ; i++)); do ./transeq "xyz$i" "xyz$i".faa -table 11; donedalam bash, tetapi saya biasanya menggunakan {a..b}sintaks rentang karena lebih cepat untuk mengetik.
Peter Cordes
4

Menggunakan find, berguna ketika file Anda tersebar di dalam direktori

find -name "xyz*" -exec ./transeq {} {}.faa -table 11 \;
Pelle
sumber
4

Dengan anggapan Anda memiliki lebih dari satu inti, dan setiap doa dapat berjalan secara independen dari yang lain, Anda akan memperoleh kecepatan yang cukup dengan gerakan paralel.

Cara yang relatif sederhana untuk melakukan ini adalah melalui -Pparameter xargs- misalnya, jika Anda memiliki 4 core:

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

Yang -n 1memberitahu xargsuntuk memilih hanya satu argumen dari daftar untuk setiap doa (secara default itu akan melewati banyak) , dan yang -P 4memberitahu untuk menelurkan 4 proses pada saat yang sama - ketika satu mati, yang baru melahirkan.

IMHO, Anda tidak perlu menginstal paralel GNU untuk kasus sederhana ini - xargssudah cukup.

ttsiodras
sumber
0

Kamu bisa memakai xarg

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

-L 1 menyebabkan lulus 1 item sekaligus

-d '\n'membuat output lsdibagi berdasarkan baris baru.

Al Mamun
sumber