İş ve işlem kimliklerini yazdırmadan arka planda bash komutlarını çalıştırma


83

Bash'de bir işlemi arka planda çalıştırmak oldukça kolaydır.

$ echo "Hello I'm a background task" &
[1] 2076
Hello I'm a background task
[1]+  Done                    echo "Hello I'm a background task"

Ancak çıktı ayrıntılıdır. İlk satıra arka plan görevinin iş kimliği ve işlem kimliği yazdırılır, ardından komutun çıktısına sahibiz, sonunda iş kimliğine, durumuna ve işi tetikleyen komuta sahibiz.

Bir arka plan görevini çalıştırmanın çıktısını, çıktının tam olarak sonunda "ve" işareti olmadan görüneceği şekilde bastırmanın bir yolu var mı? Yani:

$ echo "Hello I'm a background task" &
Hello I'm a background task

Sormamın nedeni, sekme tamamlama komutunun bir parçası olarak bir arka plan işlemi çalıştırmak istemem, dolayısıyla bu komutun çıktısının herhangi bir anlam ifade etmesi için kesintisiz olması gerekiyor.


Sanırım bash-tamamlama komut dosyalarında yaptığınız her şeye 2> / dev / null
eklemelisiniz

Yanıtlar:


98

Tamamlamayla ilgili değildir, ancak çağrıyı bir alt kabuğa koyarak bu çıktıyı bastırabilirsiniz:

(echo "Hello I'm a background task" &)

3
Teşekkürler, bu kesinlikle işe yarıyor. Ne yazık ki, bash-tamamlama işlevinden böyle bir komut dosyası çalıştırırken, bash'ın tamamlama sonuçlarını vermeden önce alt işlemin tamamlanmasını beklediği görülmektedir. Bu talihsiz bir durumdur çünkü arka planda çalışanların bash-tamamlamayla tetiklenmesinin mümkün olmadığı anlamına gelir.
Alex Spurling

13
waitArka plan işinin bitirilmesini istiyorsanız bunu kullanamazsınız .
arekolek

13

@ Shellter'ın cevabından yola çıkarak, bu benim için çalıştı:

tyler@Tyler-Linux:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1;
Hello I'm a background task
tyler@Tyler-Linux:~$

Bunun arkasındaki mantığı bilmiyorum, ancak eski bir gönderiden, reddeden bash'ın işlem kimliklerini çıktısını almasını engellediğini hatırladım.


@Tyzoid. Çözümünüzü bir bash kabuğunda (v 4.2.37) denedim ve ilginç sonuçlar aldım. 1. ;Sonunda ekleyerek aynı sonuçları aldım . (uykusuz) . 2. ANCAK echo STDERR 2>&1"sonraki" satıra eklediğimde [1]+ Done ...şeyin göründüğünü fark ettim ! . 3. Çözümüm (şimdi belirttiğim gibi) çalışıyor kshve echo STDERR 2>&1yalnızca STDERR çıktısını üretiyor. Peki, yaşa ve ikimiz için öğren. Hepinize iyi şanslar.
shellter

12

Bazı yeni bash sürümlerinde ve ksh93'te onu bir alt kabuk veya süreç grubu (yani { ... }) ile çevreleyebilirsiniz .

/home/shellter $ { echo "Hello I'm a background task" & } 2>/dev/null
Hello I'm a background task
/home/shellter $

5
Küme parantezi kullandığımda, son çıktı satırı hala gösteriliyor (neden görmediğinizden emin değilim).
Alex Spurling

Bunu tam olarak kopyaladım ama benim için çalışmıyor, yine de @AlexSpurling'in dediği gibi çıktıyı gösteriyor. Belki başkaları oy verdiğinden beri yanlış bir şey yapıyorum, ama korkarım -1 vermek zorundayım.
Mark

1
@Mark: Bununla bazı hızlı testler yaptım ve sorunun ksh93+birincil kabuğum olarak kullanmaya devam etmem olduğunu görüyorum. Bu kod, ksh'de söz verildiği gibi çalışır. ancak OP etiketlendiğinden bash, dv'nizi anlıyorum. @ Tyzoid'in cevabındaki bash testinin sonuçlarını görün. Hepinize iyi şanslar!
shellter

Bash'de bunun işe yaramadığını açıkça belirttiğiniz için -1'i kaldıracağım.
Mark

1
Benim için bu bir Bash işlevinde harika çalışıyor, aynı zamanda wait $!kabul edilen yanıt için durum böyle görünmeyen süreç de beklenebilir .
Jonatan Öström


6

Bu cevaba dayanarak daha özlü ve doğru olanı buldum:

silent_background() {
    { 2>&3 "$@"& } 3>&2 2>/dev/null
    disown &>/dev/null  # Prevent whine if job has already completed
}
silent_background date

mükemmel! ve diğer şeyler için yeniden kullanılabilir
user230910

5

Deneyin:

user@host:~$ read < <( echo "Hello I'm a background task" & echo $! )
user@host:~$ echo $REPLY
28677

Ve hem çıktıyı hem de PID'yi gizlediniz . PID'yi $ REPLY'den hala alabileceğinizi unutmayın.


1
Bu harika! Teşekkürler
Adham Atta

4

Eski bir gönderiye yanıt verdiğim için üzgünüm, ancak bunun başkaları için yararlı olduğunu ve Google'daki ilk yanıt olduğunu düşünüyorum.

Bu yöntemle (alt kabuklar) ilgili bir sorun yaşıyordum ve 'bekle' kullanıyordum. Ancak, onu bir işlevin içinde çalıştırırken, bunu yapabildim:

function a {
    echo "I'm background task $1"
    sleep 5
}

function b {
    for i in {1..10}; do
        a $i &
    done
    wait
} 2>/dev/null

Ve çalıştırdığımda:

$ b
I'm background task 1
I'm background task 3
I'm background task 2
I'm background task 4
I'm background task 6
I'm background task 7
I'm background task 5
I'm background task 9
I'm background task 8
I'm background task 10

Ve istemimi geri almam için 5 saniyelik bir gecikme var.


1

Alt kabuk çözümü işe yarıyor, ancak arka plandaki işlerde de bekleyebilmeyi (ve sonunda "Bitti" mesajını almamayı) istedim. $!bir alt kabuktan gelen mevcut etkileşimli kabukta "beklenebilir" değildir. Benim için işe yarayan tek çözüm, çok basit olan kendi bekleme işlevimi kullanmaktı:

myWait() {
  while true; do
    sleep 1; STOP=1
    for p in $*; do
      ps -p $p >/dev/null && STOP=0 && break
    done
    ((STOP==1)) && return 0
  done
}

i=0
((i++)); p[$i]=$(do_whatever1 & echo $!)
((i++)); p[$i]=$(do_whatever2 & echo $!)
..
myWait ${p[*]}

Yeterince kolay.

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.