“Xargs” çocuğun çıkışını görmezden gelir ve daha ileri işlemlere devam edilir


24

Bazen xargsgece boyunca uzun işler yürütüyorum ve bu sabah olduğu xargsgibi, tek bir özel durumda bir bölümleme hatası nedeniyle, ortada bir yerde ölen sabahları keşfetmek gerçekten can sıkıcı .

Bir xargsçocuk bile öldürülürse, daha fazla girdi işlemez:

Konsol 1:

[09:35:48] % seq 40 | xargs -i --max-procs=4 bash -c 'sleep 10; date +"%H:%M:%S {}";'
xargs: bash: terminated by signal 15
09:35:58 3
09:35:58 4
09:35:58 2
<Exit with code 125>

Konsol 2:

[09:35:54] kill 5601

Bir şekilde xargs, bir çocuk işlemi öldükten sonra daha fazla girdiyi durdurmayı ve bunun yerine işleme devam etmesini önleyebilir miyim ?


xargsSürüm 4.4.2'yi kullanıyorum debian wheezyve belirli bir sleepişlemi öldürsem bile her şey yolunda gidiyor gibi görünüyor . Hangi sürümünü xargskullanıyorsun? sorunu en son sürümde çözmüş olabilirler.
Kannan Mohan

Partiye biraz geç, peki xargs ... bash -c '...;exit 0'ya xargs ... bash -c '... || echo erk'
peki

Bunun parallel -j 1olası bir hack çözümü olduğuna dikkat edin .
barrycarter

Yanıtlar:


25

Hayır yapamazsın. Gönderen xargssavannah.gnu.org kaynaklarca :

if (WEXITSTATUS (status) == CHILD_EXIT_PLEASE_STOP_IMMEDIATELY)
  error (XARGS_EXIT_CLIENT_EXIT_255, 0,
         _("%s: exited with status 255; aborting"), bc_state.cmd_argv[0]);
if (WIFSTOPPED (status))
  error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
         _("%s: stopped by signal %d"), bc_state.cmd_argv[0], WSTOPSIG (status));
if (WIFSIGNALED (status))
  error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
         _("%s: terminated by signal %d"), bc_state.cmd_argv[0], WTERMSIG (status));
if (WEXITSTATUS (status) != 0)
  child_error = XARGS_EXIT_CLIENT_EXIT_NONZERO;

Bu çekin etrafında veya çağıran işlevin etrafında bayrak yok. Max procs ile ilgili gibi görünüyor, sanırım mantıklı geliyor: max procs'u yeterince yükseğe koyarsanız, asla elde edemeyeceğiniz sınıra kadar kontrol etmeyi zahmete sokmaz.

Yapmaya çalıştığınız şey için daha iyi bir çözüm GNU Make'ı kullanmak olabilir :

TARGETS=$(patsubst %,target-%,$(shell seq 1 40))

all: $(TARGETS)

target-%:
    sleep 10; date +"%H:%M:%S $*"

Sonra:

$ make -k -j4 

Aynı etkiye sahip olacak ve size çok daha iyi kontrol sağlayacaktır.


9

Görünüşe göre, en bariz kolloyalizmlerden biri sadece diğer öneriler tarafından veriliyor.

Yani, aşağıdakileri kullanabilirsiniz:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

"başarıyı zorlamak" için.

Bu, teklifin lornix'in önerileri boyunca olduğunu (sadece pek fazla kelimeyle değil) unutmayın.

Her neyse, bu gerçek süreç çıkış durumunu etkin bir şekilde görmezden geldiği için, ölüm sonrası analiz için alt işlem durumunu bir şekilde kaydettiğinizden emin olun. Örneğin:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed; (true)'

trueBurada biraz gereksiz ve bu yüzden bu daha iyi olarak yazılabilir geçerli:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Muhtemelen 'başarısız' dosyaya ne zaman dokunamadığını bilmek istiyoruz. Başka bir deyişle, artık başarısızlığı görmezden gelmiyoruz, not alıyoruz ve devam ediyoruz.

Ve bu sorunun özyinelemeli doğasını düşündükten sonra, belki de xargs'ın neden başarısızlığı görmezden gelmeyi kolaylaştırmadığını tam olarak görüyoruz . Çünkü bu asla iyi bir fikir değildir - bunun yerine geliştirdiğiniz süreç içinde hata işlemeyi geliştirmelisiniz. Bununla birlikte, bu fikrin "Unix felsefesinin" kendisinde daha doğal olduğuna inanıyorum.

Son olarak, sanırım James Youngman’ın tavsiye trapettiği şekilde, buna benzer bir şekilde kullanılabileceğini önerdiği şey de budur . Yani, sorunu görmezden gelmeyin ... tuzağa düşürün ve sorun ya da bir gün uyandırın ve alt programların hiçbirinin başarılı olamadığını anlayın ;-)


3

Kullanım trap:

$ seq 40 | xargs -i --max-procs=4 bash -c \
 'trap "echo erk; exit 1" INT TERM;  sleep 10; date +"%H:%M:%S {}";' fnord
16:07:39 2
16:07:39 4
erk
16:07:39 1
^C
erk
erk
erk
erk

Alternatif olarak, kabuktan sinyal işleyicilerini de ayarlayabileceğiniz başka bir dile geçin.

Ayrıca, sonradan bash -c foo..alması gereken değeri $0(burada fnord) belirtmeniz gerektiğini, böylece üretilen ilk kelimenin seqyenilmemesi gerektiğini unutmayın.


2

Ölen programın sinyalini 'yemek' için oraya başka bir komut koyun.

Örneğinizi denedim, baştan beri sorunu kanıtlamak için gösterildiği gibi ... 'öldürme uykusu' uyku sürecini öldürür, bası keser ve xargs sonlandırır.

Bir test olarak, '/ usr / bin / time', xargs ve bash ... arasında bir 'başka bir komut çalıştır' tipi komutu yapıştırdım. Bu sefer (punto yok), öldürme uykusu uyku sürecini öldürür, ancak xargs devam eder.

Zamanın çıktısını / dev / null değerine yönlendirirsiniz ve bu tam olarak aradığınızı, mevcut sürecinizin büyük bir yeniden yazması olmadan yapar.

Bir anlığına düşünürsem, '/ usr / bin / time' den stderr geveze olmadan aynı şeyi yapmak için başka bir programla gelebileceğimi hayal ediyorum. Hatta bir tane bile yazsam, bu sadece bir 'çatal' (ya da exec () türevi).

'/ Usr / bin / time' ifadesini kullanmayı unutmayın, çünkü bash'dan gelen yerleşik 'time' ifadesinin sinyalin aynı “yeme” sini yapacağından emin değilim.


1
timeBu amaç için iyi bir alternatif env, çünkü yaptığı tek şey çalıştığı programın ortamına sıfır veya daha fazla isteğe bağlı değişken eklemek. Kendi çıktısını vermez ve çağrılan programın dönüş kodu ne denirse oraya geri gönderilir env.
James Sneeringer

{Chuckle} Bunu yazdıktan bir süre sonra bunu düşündüm. Zaman, "bir şeyi çalıştır" komutu olarak akla gelen ilk şeydi. Yine de güzel çalışıyor. Tebrikler ve teşekkür ederim.
lornix

2

Ne benim için ne timede envişe yaradı (çocuk programlarının getirilerini geçtiler) bu yüzden şunu yazdım bliss:

#!/bin/sh
"$@"
exit 0

sonra chmod u+x ~/bliss

ve benzeri bir şey find_or_similar | xargs ~/bliss fatally_dying_program.sh

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.