Запуск команд bash у фоновому режимі без друку ідентифікаторів роботи та обробки


83

Запустити процес у фоновому режимі в bash досить просто.

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

Однак результат є багатослівним. У першому рядку друкується ідентифікатор завдання та ідентифікатор процесу фонового завдання, потім ми отримуємо вихідні дані команди, нарешті, ми маємо ідентифікатор завдання, його статус та команду, яка ініціювала роботу.

Чи є спосіб придушити вихідний результат запуску фонового завдання таким чином, щоб результат виглядав точно так, як це було б без амперсанда в кінці? Тобто:

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

Причина, по якій я запитую, полягає в тому, що я хочу запустити фоновий процес як частину команди завершення вкладки, тому вихід цієї команди повинен бути безперервним, щоб мати якийсь сенс.


Думаю, вам слід додати 2> / dev / null до всього, що ви робите в сценаріях завершення bash
sehe

Відповіді:


98

Це не пов’язано із завершенням, але ви можете придушити цей результат, помістивши виклик у підшарку:

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

3
Дякую, це точно працює. На жаль, під час запуску подібного сценарію з функції завершення bash, здається, що bash чекає завершення підпроцесу, перш ніж давати результати завершення. Це прикро, оскільки це означає, що, здається, неможливо змусити фонових працівників запускати баш-завершення.
Alex Spurling,

13
Ви не можете використовувати це, якщо хочете, щоб waitфонове завдання закінчилося.
arekolek

13

На основі відповіді @ shellter, це спрацювало для мене:

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:~$

Я не знаю аргументів цього, але зі старого допису я пам’ятав, що відмовляння заважає bash виводити ідентифікатори процесу.


@ Тизоїд. Я спробував ваше рішення в оболонці bash (v 4.2.37) і мав цікаві результати. 1. Я отримав ті самі результати, просто додавши ;в кінці. (без сну). 2.АЛЕ зауважив, що коли я додав echo STDERR 2>&1у рядок "наступний", то [1]+ Done ...річ з'явилася! . 3. Моє рішення (як я вже зазначав) працює kshі echo STDERR 2>&1видає лише результат STDERR. Ну, живи і вчись для нас обох. Всім удачі.
обстріл

12

У деяких новіших версіях bash та ksh93 ви можете оточити його допоміжною оболонкою або групою процесів (тобто { ... }).

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

5
Коли я використовую фігурні дужки, останній рядок виводу все одно відображається (я не впевнений, чому ви цього не бачите).
Alex Spurling,

Я скопіював це точно, але це не працює для мене, він все ще відображає результат, як говорить @AlexSpurling. Можливо, я роблю щось неправильно, оскільки інші це підтримали, але, боюся, мені доведеться дати -1.
Марк

1
@Mark: Я щойно зробив кілька швидких тестів з цим, і я бачу проблему в тому, що я продовжую використовувати ksh93+як свою оболонку primariy. Цей код працює так, як обіцяно у ksh. але оскільки ОП позначено тегом, bashя розумію твій DVD. Див. Результати тестування bash на відповідь @ Tyzoid. Всім удачі!
обстріл

Оскільки ви зрозуміли, що це не працює в bash, я видалю -1.
Марк

1
Для мене це чудово працює у функції Bash, також можна зачекати процес, wait $!який, схоже, не відповідає прийнятій відповіді.
Jonatan Öström


6

На основі цієї відповіді я придумав більш стислий і правильний:

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

ідеально! і багаторазовий для інших речей
user230910

5

Спробуйте:

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

І ви сховали як вихідні дані, так і PID . Зверніть увагу, що ви все ще можете отримати PID із $ REPLY


1
Це ідеально! Дякую
Адхам Атта

4

Вибачте за відповідь на стару публікацію, але я вважаю, що це корисно для інших, і це перша відповідь у Google.

У мене виникла проблема з цим методом (під оболонками) та використанням "очікування". Однак, коли я запускав його всередині функції, я зміг зробити це:

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

І коли я запускаю його:

$ 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

І є затримка 5 секунд, перш ніж я отримаю запит.


1

Рішення під оболонки працює, але я також хотів мати можливість чекати на фонових завданнях (і не мати повідомлення "Готово" в кінці). $!з підраковини не є "очікуваним" у поточній інтерактивній оболонці. Єдиним рішенням, яке працювало для мене, було використання власної функції очікування, яка дуже проста:

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[*]}

Досить просто.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.