"Варіалізуйте" амперсанд (фоновий процес)


9

Я хочу знати, чи є спосіб помістити ampersand у змінну і все ж використовувати її для надсилання процесу на задній план.

Це працює:

BCKGRND=yes
if [ "$BCKGRND" = "yes" ]; then
    sleep 5 &
else
    sleep 5
fi

Але хіба не було б круто виконати ці п'ять рядків лише одним? Так:

BCKGRND='&'
sleep 5 ${BCKGRND}

Але це не працює. Якщо BCKGRND не встановлений, він працює, але коли він встановлений, він інтерпретується як буквальне "&" та помилки.


після використання останнього ampersand echo $!повертає PID
noobninja

Відповіді:


9

Використовувати змінну для фонового виклику неможливо, тому що розширення змінної відбувається після розбору командного рядка для операторів управління (наприклад, &&та &).

Ще одним варіантом буде перетворення викликів у функцію:

mayberunbg() {
  if [ "$BCKGRND" = "yes" ]; then
    "$@" &
  else
    "$@"
  fi
}

... а потім встановіть змінну за потребою:

$ BCKGRND=yes mayberunbg sleep 3
[1] 14137
$
[1]+  Done                    "$@"
# or
$ BCKGRND=yes
$ mayberunbg sleep 3
[1] 14203
$
[1]+  Done                    "$@"
$ BCKGRND=no mayberunbg sleep 3
# 3 seconds later
$

Що, ні ed? +1 у будь-якому випадку, це найчистіше рішення.
Стівен Кітт

LOL @StephenKitt; тепер передачі повороту
Джефф Шаллер

Мені сподобалась відповідь eval за її простоту, але моя реальна команда в реальному світі, яку я хотів, щоб тло було занадто складним із занадто великою кількістю змінних в ньому, щоб було зручно використовувати eval. @ jeff-schaller дав відповідь, яка вказувала мені в напрямку, в якому я йшов. Замість функції, проте, я поставив всю команду в змінну, а потім застосував його, якщо стиль заяви, щоб виконати команду з & без &.
BrowncoatOkie

11

Ви можете гортати речі та змінювати "переднє планування":

FOREGROUND=fg
sleep 5 & ${FOREGROUND}

Встановіть FOREGROUNDна trueабо спорожнити , щоб запустити процес у фоновому режимі. (Налаштування FOREGROUNDдля trueзапуску у фоновому режимі, мабуть, заплутано! Відповідні назви змінних залишаються як вправа для читача.)


4
це добре, але він не працюватиме в оболонці без контролю роботи (тобто будь-який сценарій, якщо set -mне використовувався).
mosvy

9

Вам, ймовірно, доведеться використовувати eval:

eval "sleep 5" "$BCKGRND"

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


2
Відповідь, що містить, evalповинна містити попередження, що з цим слід поводитися обережно. Див., Наприклад, цю відповідь .
Ральф

Я не розумію, в чому проблема полягає в "$BCKGRND"оцінці порожнього аргументу.
mosvy

2
@Ralf в цьому випадку абсолютно не має значення . Нічого особливого в eval немає - наприклад, ви можете виконувати команди за допомогою арифметичних розширень. Можливо, взагалі повинно бути таке попередження щодо використання bash (або будь-якої подібної оболонки) ;-)
mosvy

1
@Kusalananda evalприєднає свої аргументи з пробілами, перш ніж робити власне оцінку. Просто спробуйте: eval printf "'{%s}\n'" foo "" "" "". eval foo "" "" "" ""абсолютно схожий на eval foo, незалежно від того, що IFSчи інше.
mosvy

1
Команда, котра eval'ed, повинна містити подвійні лапки, якщо вона містить якісь спеціальні символи, наприклад eval 'sleep $TIMEOUT' "$BACKGROUND". Інакше ви можете отримати подвійні розширення, якщо змінна розшириться на іншу змінну або містить спеціальні символи. Також вкладене цитування може стати складним.
Бармар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.