Как сохранить выходные данные команды, которая изменяет среду в переменную?
Я использую оболочку bash.
Предположим, что у меня есть:
function f () { a=3; b=4 ; echo "`date`: $a $b"; }
И теперь я могу использовать команды для запуска f
:
$ a=0; b=0; f; echo $a; echo $b; echo $c
Sat Jun 28 21:27:08 CEST 2014: 3 4
3
4
но я хотел бы сохранить вывод f
переменной c
, поэтому я попытался:
a=0; b=0; c=""; c=$(f); echo $a; echo $b; echo $c
но, к сожалению, у меня есть:
0
0
Sat Jun 28 21:28:03 CEST 2014: 3 4
поэтому у меня нет никаких изменений окружающей среды здесь.
Как сохранить выходные данные команды (не только функции) в переменную и сохранить изменения среды?
Я знаю, что $(...)
открывается новый подоболочек и в этом проблема, но можно ли сделать какой-то обходной путь?
bash
environment-variables
output
Фарамир
источник
источник
$a
и$b
являются локальными переменными в вашейf
функции. Вы могли быexport
их, но это кажется отрывочным.…; f; echo $a; …
результаты3
отображаются,f
как и изменение переменной оболочки (а не только ее локальной переменной).Ответы:
Если вы используете Bash 4 или более позднюю версию, вы можете использовать сопроцессы :
будет выводить
coproc
создает новый процесс, выполняющий данную команду (здесь,cat
). Он сохраняет PIDCOPROC_PID
и стандартные дескрипторы выходных / входных файлов в массивеCOPROC
(какpipe(2)
, например , или смотрите здесь или здесь ).Здесь мы запускаем функцию со стандартным выводом, указывающим на запущенный нами сопроцесс
cat
, а затемread
из него. Так какcat
просто выплевывает свой ввод обратно, мы получаем вывод функции в нашу переменную.exec {COPROC[1]}>&-
просто закрывает файловый дескриптор, чтобыcat
не ждать вечно.Обратите внимание, что
read
занимает только одну строку за раз. Вы можете использовать,mapfile
чтобы получить массив строк, или просто использовать дескриптор файла, однако вы хотите использовать его по-другому.exec {COPROC[1]}>&-
работает в текущих версиях Bash, но более ранние версии 4- й серии требуют , чтобы сохранить дескриптор файла в простой переменной первой:fd=${COPROC[1]}; exec {fd}>&-
. Если ваша переменная не установлена, она закроет стандартный вывод.Если вы используете версию Bash для 3-х серий, вы можете получить тот же эффект
mkfifo
, но это не намного лучше, чем использовать настоящий файл в тот момент.источник
exec {COPROC[1]}>&-
команда (по крайней мере, иногда) немедленно завершает сопроцесс , поэтому ее выходные данные больше не доступны для чтения.coproc { cat; sleep 1; }
кажется, работает лучше. (Возможно, вам придется увеличить,1
если вы читаете более одной строки.)Если вы уже рассчитываете на то, что тело будет
f
выполнено в той же оболочке, что и вызывающая программа, и, таким образом, сможете изменять переменные, такие какa
иb
, почему бы не сделать функцию просто установленнойc
? Другими словами:Одна из возможных причин может заключаться в том, что выходная переменная должна иметь разные имена (c1, c2 и т. Д.) При вызове в разных местах, но вы можете решить эту проблему, установив функцию c_TEMP и сделав вызывающую функцию и
c1=$c_TEMP
т. Д.источник
Это клуге, но попробуй
(и, необязательно,
rm c.file
).источник
mktemp
, но я не хотел бы создавать дополнительные файлы.Просто назначьте все переменные и запишите результат одновременно.
Теперь, если вы делаете:
Ваш вывод:
Обратите внимание, что это полностью переносимый код POSIX. Я первоначально установлен
c=
на''
строку с нулевым символом , поскольку расширение параметр ограничивает одновременное задание переменной + оценку либо только числовые (например$((var=num))
) или с нулевыми или несуществующих значений - или, другими словами, вы не можете одновременно установить и оценить переменную для произвольной строки если этой переменной уже присвоено значение. Поэтому я просто проверяю, что он пуст, прежде чем пытаться. Если бы я не опустелc
до того, как попытаться назначить его, расширение вернуло бы только старое значение.Просто чтобы продемонстрировать:
newval
это не назначается$c
рядный , потому чтоoldval
расширяется в${word}
, в то время как рядный$((
арифметическое=
задание))
всегда происходит. Но если$c
не имеетoldval
и пусто или не установлено ...... тогда
newval
сразу назначается и расширяется в$c
.Все другие способы сделать это включают некоторую форму вторичной оценки. Например, скажем, я хотел назначить вывод
f()
переменной, названнойname
в одной точке иvar
в другой. Как написано в настоящее время, это не будет работать без установки переменной var в области действия вызывающего. Другой способ может выглядеть так:Ниже приведен лучший форматированный пример, но, как указано выше, вывод выглядит так:
Или с разными
$ENV
аргументами:Вероятно, самая сложная вещь, которую нужно сделать правильно, когда дело доходит до двукратной оценки, - убедиться, что переменные не разбивают кавычки и не выполняют случайный код. Чем больше раз оценивается переменная, тем сложнее она становится. Расширение параметров здесь очень помогает, и использование
export
в отличие отeval
него намного безопаснее.В приведенном выше примере
f()
первый назначает$fout
на''
строку с нулевым символом , а затем устанавливает позиционные Params испытанию для допустимых имен переменных. Если оба теста не пройдены, отправляется сообщениеstderr
иfout
назначается значение по умолчанию$fout_name
. Однако независимо от тестов$fout_name
всегда присваивается либоfout
указанное вами имя, либо,$fout
и, опционально, указанному имени всегда присваивается выходное значение функции. Чтобы продемонстрировать это, я написал этот маленькийfor
цикл:Он играет с именами переменных и расширениями параметров. Если у вас есть вопрос, просто спросите. Это только запускает те же несколько строк в функции, уже представленной здесь. Стоит отметить , по крайней мере , хотя , что
$a
и$b
переменные ведут себя по- разному в зависимости от того, являются ли они определены при вызове, или установить уже. Темfor
не менее, они почти ничего не делают, кроме как форматируют набор данных и предоставляютf()
. Посмотри:источник