У меня есть следующая рекурсивная функция для установки переменных среды:
function par_set {
PAR=$1
VAL=$2
if [ "" != "$1" ]
then
export ${PAR}=${VAL}
echo ${PAR}=${VAL}
shift
shift
par_set $*
fi
}
Если я вызываю его сам по себе, он устанавливает переменную и выводит stdout:
$ par_set FN WORKS
FN=WORKS
$ echo "FN = "$FN
FN = WORKS
Перенаправление stdout в файл также работает:
$ par_set REDIR WORKS > out
cat out
REDIR=WORKS
$ echo "REDIR = "$REDIR
REDIR = WORKS
Но, если я перенаправлю stdout другой команде, переменная не будет установлена:
$ par_set PIPE FAILS |sed -e's/FAILS/BARFS/'
PIPE=BARFS
$ echo "PIPE = "$PIPE
PIPE =
Почему канал не позволяет функции экспортировать переменную? Есть ли способ исправить это, не прибегая к временным файлам или именованным каналам?
Решено:
Рабочий код благодаря Жилю:
par_set $(echo $*|tr '=' ' ') > >(sed -e's/^/ /' >> ${LOG})
Это позволяет скрипту вызываться так:
$ . ./script.sh PROCESS_SUB ROCKS PIPELINES=NOGOOD
$ echo $PROCESS_SUB
ROCKS
$ echo $PIPELINES
NOGOOD
$ cat log
7:20140606155622162731431:script.sh:29581:Parse Command Line parameters. Params must be in matched pairs separated by one or more '=' or ' '.
PROCESS_SUB=ROCKS
PIPELINES=NOGOOD
Проект размещен на bitbucket https://bitbucket.org/adalby/monitor-bash, если вы заинтересованы в полном коде.
Это не работает, потому что каждая сторона канала работает в подоболочке
bash
, а переменные, заданные в подоболочке, являются локальными для этой подоболочки.Обновить:
Похоже, что легко передать переменные из родительского в дочернюю оболочку, но действительно трудно сделать это другим способом. Некоторые обходные пути: именованные каналы, временные файлы, запись в стандартный вывод, чтение в родительском файле и т. Д.
Некоторые ссылки:
http://mywiki.wooledge.org/BashFAQ/024
https://stackoverflow.com/q/15541321/3565972
https://stackoverflow.com/a/15383353/3565972
http://forums.opensuse.org/showthread .php / 458979-Как-экспорт переменной-в-субоболочке-обратно из к родителям
источник
$$
одинаково как для родительских, так и для дочерних оболочек. Вы можете использовать,$BASHPID
чтобы получить pid subshell. Когда яecho $$ $BASHPID
внутри,par_set
я получаю разные пид.Вы указываете на подоболочки - которые можно обойти с помощью некоторой ошибки в оболочке вне конвейера - но более сложная часть проблемы связана с параллелизмом конвейера .
Все члены процесса конвейера запускаются сразу , поэтому проблему легче понять, если вы посмотрите на это так:
Процессы конвейера не могут наследовать значения переменных, потому что они уже отключены и работают до того, как переменная когда-либо будет установлена.
Я не могу понять, в чем смысл вашей функции - какой цели она служит, чего
export
еще нет? Или даже простоvar=val
? Например, вот снова почти тот же конвейер:И с
export
:Таким образом, ваша вещь может работать как:
Который будет записывать в
sed
выходной файл файла и доставлять его в вашу функцию как разделение оболочки"$@"
.Или, альтернативно:
Если бы я собирался написать вашу функцию, она бы выглядела так:
источник
|pipeline | sh
sh
. Он уже используетexport
.