Bash

在管道中呼叫我的函式時未設置環境變數

  • June 6, 2014

我有以下遞歸函式來設置環境變數:

function par_set {
 PAR=$1
 VAL=$2
 if [ "" != "$1" ]
 then
   export ${PAR}=${VAL}
   echo ${PAR}=${VAL}
   shift
   shift
   par_set $*
 fi
}

如果我自己呼叫它,它會設置變數並回顯到標準輸出:

$ par_set FN WORKS
FN=WORKS
$ echo "FN = "$FN
FN = WORKS

將標準輸出重定向到文件也可以:

$ 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 =

為什麼管道會阻止函式導出變數?有沒有辦法在不使用臨時文件或命名管道的情況下解決這個問題?

解決了:

感謝 Gilles 的工作程式碼:

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上。

管道的每一部分(即管道的每一側)都在一個單獨的程序中執行(稱為子shell,當shell派生出一個子程序來執行部分腳本時)。在par_set PIPE FAILS |sed -e's/FAILS/BARFS/'中,PIPE變數設置在執行管道左側的子程序中。這種變化不會反映在父程序中(環境變數不會在程序之間傳遞,它們只會被子程序繼承。

管道的左側始終在子外殼中執行。一些 shell(ATT ksh、zsh)在父 shell 的右側執行;大多數還在子shell中執行右側。

如果您想重定向腳本的一部分的輸出並在父 shell 中執行該部分,在 ksh/bash/zsh 中,您可以使用程序替換

par_set PROCESS SUBSTITUTION > >(sed s/ION/ED/)

使用任何 POSIX shell,您都可以將輸出重定向到命名管道。

mkfifo f
<f grep NAMED= &
par_set NAMED PIPE >f

哦,你缺少圍繞變數替換的引號,你的程式碼在諸如par_set name 'value with spaces' star '*'.

export "${PAR}=${VAL}"
…
par_set "$@"

引用自:https://unix.stackexchange.com/questions/134735