«Вариабилизация» амперсанда (фоновый процесс)


9

Я хочу знать, есть ли способ поместить амперсанд в переменную и по-прежнему использовать его для отправки процесса в фоновый режим.

Это работает:

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

Но разве не здорово было бы выполнить эти пять строк одной? Вот так:

BCKGRND='&'
sleep 5 ${BCKGRND}

Но это не работает. Если BCKGRND не установлен, он работает - но когда он установлен, он интерпретируется как литерал '&' и выдает ошибки.


после использования echo $!
конечного

Ответы:


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. @ Джефф-Шаллер дал ответ, который указал мне направление, в котором я пошел. Однако вместо функции я поместил всю команду в переменную, а затем использовал его стиль оператора if для выполнения команды с или без &.
BrowncoatOkie

11

Вы можете перевернуть вещи и изменить «приоритет»:

FOREGROUND=fg
sleep 5 & ${FOREGROUND}

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


4
это хорошо, но это не будет работать в оболочке без управления заданиями (т. е. любой сценарий, если он set -mне использовался).
Мосви

9

Вам, вероятно, придется использовать eval:

eval "sleep 5" "$BCKGRND"

evalзаставляет оболочку переоценивать приведенные аргументы. &Таким образом, литерал будет интерпретироваться как &конец команды, а не как аргумент команды, помещая команду в фоновом режиме.


2
Содержащий ответ evalдолжен содержать предупреждение, что с этим следует обращаться осторожно. Смотрите, например, этот ответ .
Ralf

Я не понимаю, в чем проблема с "$BCKGRND"оценкой пустого аргумента.
Мосви

2
@Ralf абсолютно не имеет значения в этом случае . В eval нет ничего особенного - например, вы можете выполнять команды через арифметические расширения. Может быть, должно быть такое предупреждение против использования bash (или любой подобной оболочки) вообще ;-)
mosvy

1
@Kusalananda evalобъединит свои аргументы с пробелами, прежде чем делать фактический eval. Просто попробуйте eval printf "'{%s}\n'" foo "" "" "". eval foo "" "" "" ""полностью похож на eval foo, независимо от того, что IFSили другое.
Мосви

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