Bash betiği sınırlı sayıda komutu paralel olarak işliyor


196

Şöyle bir bash betiği var:

#!/bin/bash
wget LINK1 >/dev/null 2>&1
wget LINK2 >/dev/null 2>&1
wget LINK3 >/dev/null 2>&1
wget LINK4 >/dev/null 2>&1
# ..
# ..
wget LINK4000 >/dev/null 2>&1

Ancak komut bitene kadar her satırı işlemek, bir sonrakine geçmek çok zaman alıcıdır, örneğin 20 satır işlemeyi bitirdikten sonra 20 satır daha işlemek istiyorum.

wget LINK1 >/dev/null 2>&1 &Komutu arka plana göndermeyi ve devam etmeyi düşündüm , ancak burada 4000 satır var, bu da performans sorunları yaşayacağım anlamına geliyor, aynı anda kaç süreç başlatmam gerektiğinden bahsetmiyorum, bu iyi değil fikir.

Şu anda düşündüğüm bir çözüm, komutlardan birinin hala çalışıp çalışmadığını kontrol etmektir, örneğin 20 satırdan sonra bu döngüyü ekleyebilirim:

while [  $(ps -ef | grep KEYWORD | grep -v grep | wc -l) -gt 0 ]; do
sleep 1
done

Tabii ki bu durumda satırın sonuna & eklemeliyim! Ama bunun doğru bir yol olmadığını hissediyorum.

Peki nasıl aslında her 20 satır birlikte gruplandırmak ve sonraki 20 satır gitmeden önce bitirmek için beklemek nasıl, bu komut dosyası dinamik olarak oluşturulur, bu yüzden ben üretilirken üzerinde istediğim herhangi bir matematik yapabilirim, ama yapmak zorunda DEĞİLDİR wget kullanın, bu sadece bir örnekti, bu yüzden wget'e özgü herhangi bir çözüm bana iyi gelmeyecek.


1
waitburada doğru cevaptır, ancak while [ $(ps …çok daha iyi yazılırsınız while pkill -0 $KEYWORD…- proktools kullanarak … yani, belirli bir ada sahip bir sürecin hala çalışıp çalışmadığını kontrol etmek için meşru nedenlerden dolayı.
kojiro

Bu sorunun yeniden açılması gerektiğini düşünüyorum. "Olası çift" KG, paralel olarak sınırlı sayıda program çalıştırmakla ilgilidir . 2-3 komut gibi. Ancak bu soru, komutları örneğin bir döngüde çalıştırmaya odaklanmıştır. (bkz. "ancak 4000 satır var").
VasiliNovikov

@VasyaNovikov Hem bu sorunun hem de kopyaların tüm cevaplarını okudunuz mu? Bu soruya verilen her bir cevap, yinelenen sorunun cevaplarında da bulunabilir. Bu tam olarak yinelenen bir sorunun tanımıdır. Komutları bir döngüde çalıştırıp çalıştırmamanız kesinlikle fark etmez.
robinCTS

@robinCTS kesişme noktaları vardır, ancak soruların kendileri farklıdır. Ayrıca, bağlantılı KG'deki en popüler cevaplardan 6 tanesi sadece 2 işlemle ilgilidir.
VasiliNovikov

2
Bu soruyu tekrar açmanızı öneriyorum çünkü cevabı daha net, daha temiz, daha iyi ve bağlantılı sorunun cevabından çok daha yüksek oranda değerlendirildi, ancak üç yıl daha yeni.
Dan Nissenbaum

Yanıtlar:


331

Yerleşik waitolanı kullanın :

process1 &
process2 &
process3 &
process4 &
wait
process5 &
process6 &
process7 &
process8 &
wait

Yukarıdaki örnek için, 4 süreç process1... process4arka planda başlatılacak ve kabuk sonraki sete başlamadan önce bu işlemlerin tamamlanmasını bekleyecekti.

Gönderen GNU kılavuzda :

wait [jobspec or pid ...]

Her işlem kimliği pid'i veya iş belirtimi jobspec tarafından belirtilen alt işlemin çıkmasını bekleyin ve beklenen son komutun çıkış durumunu döndürün. Bir iş spesifikasyonu verilirse, işteki tüm süreçler beklenir. Herhangi bir argüman verilmezse, şu anda aktif olan tüm alt süreçler beklenir ve dönüş durumu sıfırdır. Ne jobspec ne de pid kabuğun etkin bir alt işlemini belirtmezse, dönüş durumu 127 olur.


14
Yani temeldei=0; waitevery=4; for link in "${links[@]}"; do wget "$link" & (( i++%waitevery==0 )) && wait; done >/dev/null 2>&1
kojiro

18
Her sürecin aynı anda biteceğinden emin değilseniz, bu kötü bir fikirdir. Mevcut toplam işleri belirli bir sınırda tutmak için yeni işlere başlamalısınız .... paralel cevap.
testere

1
Bunu bir döngüde yapmanın bir yolu var mı?
DomainsFeatured

Bunu denedim ama bir blokta yapılan değişken atamaları sonraki blokta mevcut değil gibi görünüyor. Bu ayrı süreçler oldukları için mi? Değişkenleri ana sürece geri aktarmanın bir yolu var mı?
Bobby

97

Bkz. Paralel . Sözdizimi buna benzer xargs, ancak komutları paralel olarak çalıştırır.


13
Bu, kullanmaktan daha iyidir wait, çünkü bir sonraki işe başlamadan önce tüm partinin bitmesini beklemek yerine, yeni işleri eski işler olarak tamamlamaya özen gösterir.
chepner

5
Örneğin, bir dosyadaki bağlantıların listesine sahipseniz, bunu bir seferde cat list_of_links.txt | parallel -j 4 wget {}dört wgets çalıştıracak şekilde yapabilirsiniz .
Bay Llama

5
Kasabanın yerine pexec adı verilen yeni bir çocuk var parallel.
slashsbin

2
Bir örnek vermek daha yararlı olacaktır
jterm

1
parallel --jobs 4 < list_of_commands.sh, List_of_commands.sh (örneğin tek bir komutla bir dosyanın nerede wget LINK1olmadan, not &her satırda). Arka planda çalışmasına izin vermek için CTRL+Zve bgsonrasında gerekebilir .
weiji14

71

Aslında, xargs olabilir sizin için paralel komutları çalıştırın. Bunun için özel bir -P max_procskomut satırı seçeneği var. Bkz man xargs.


2
+100 bu harika çünkü inşa edilmiş ve kullanımı çok basit ve tek
Clay

Ekstra paketler / bağımlılıklar gerekmediği için küçük kaplar için harika!
Marco Roy

1
Örnekler için bu soruya bakın: stackoverflow.com/questions/28357997/…
Marco Roy

7

20 işlemi çalıştırabilir ve şu komutu kullanabilirsiniz:

wait

Tüm arka plan işleriniz bittiğinde komut dosyanız bekleyecek ve devam edecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.