환경 변수를 설정하는 다음과 같은 재귀 함수가 있습니다.
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 =
파이프가 함수가 변수를 내 보내지 못하게하는 이유는 무엇입니까? 임시 파일이나 명명 된 파이프에 의존하지 않고이 문제를 해결할 수있는 방법이 있습니까?
해결 :
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
전체 코드에 관심이있는 경우 비트 버킷 https://bitbucket.org/adalby/monitor-bash 에서 호스팅되는 프로젝트 .
답변
파이프 라인의 각 부분 (즉, 파이프의 각 측면)은 별도의 프로세스 (쉘 이 스크립트의 일부를 실행하기 위해 서브 프로세스를 포크 할 때 서브 쉘이라고 함)에서 실행됩니다 . 에서 par_set PIPE FAILS |sed -e's/FAILS/BARFS/'
의 PIPE
변수는 파이프의 좌측을 실행하는 서브 프로세스에서 설정된다. 이 변경 사항은 상위 프로세스에 반영되지 않습니다 (환경 변수는 프로세스간에 전송되지 않으며 하위 프로세스에 의해서만 상속됩니다).
파이프의 왼쪽은 항상 서브 쉘에서 실행됩니다. 일부 쉘 (ATT ksh, zsh)은 상위 쉘에서 오른쪽을 실행합니다. 대부분은 서브 쉘에서 오른쪽을 실행합니다.
스크립트의 일부 출력을 재지 정하고 ksh / bash / zsh의 상위 쉘에서 해당 부분을 실행하려면 프로세스 대체를 사용할 수 있습니다 .
par_set PROCESS SUBSTITUTION > >(sed s/ION/ED/)
POSIX 셸을 사용하면 출력을 명명 된 파이프로 리디렉션 할 수 있습니다.
mkfifo f
<f grep NAMED= &
par_set NAMED PIPE >f
아, 그리고 변수 대체 에 대한 따옴표 가 누락되었습니다 par_set name 'value with spaces' star '*'
. 코드는 다음과 같습니다 .
export "${PAR}=${VAL}"
…
par_set "$@"
답변
파이프의 각면이의 서브 쉘에서 실행되고 서브 쉘에 bash
설정된 변수가 해당 서브 쉘에 로컬 이기 때문에 작동하지 않습니다 .
최신 정보:
부모에서 자식 셸로 변수를 전달하는 것은 쉽지만 실제로 는 다른 방법으로 수행하는 것이 어렵습니다. 일부 해결 방법은 파이프, 임시 파일, stdout에 쓰기 및 상위에서 읽기 등입니다.
일부 참고 문헌 :
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- 어떻게 내보내기-변수-서브 쉘-백-아웃-부모
답변
파이프 라인 외부의 쉘에서 약간의 문제가 발생할 수있는 서브 쉘을 지적하지만 문제의 더 어려운 부분은 파이프 라인의 동시성과 관련이 있습니다.
파이프 라인의 모든 프로세스 멤버는 한 번에 시작 하므로 다음과 같이 보면 문제를 이해하기가 더 쉬울 수 있습니다.
{ sleep 1 ; echo $((f=1+2)) >&2 ; } | echo $((f))
###OUTPUT
0
...
3
파이프 라인 프로세스는 변수 값을 설정하기 전에 변수 값이 이미 꺼져 있고 실행 중이므로 변수 값을 상속 할 수 없습니다.
나는 당신의 기능의 요점이 무엇인지 이해할 수 없습니다- export
아직 어떤 목적을 달성 하지 못합니까? 아니면 그냥 var=val
? 예를 들어 다음은 거의 동일한 파이프 라인입니다.
pipeline() {
{ sleep 1
echo "f=$((f=f+1+2))" >&3
} | echo $((f)) >&2
} 3>&1
f=4 pipeline
###OUTPUT
4
...
f=7
그리고 export
:
export $(f=4 pipeline) ; pipeline
###OUTPUT:
4
7
...
f=10
그래서 당신의 일은 다음과 같이 작동 할 수 있습니다 :
par_set $(echo PIPE FAILS |
sed 's/FAIL/WORK/;/./w /path/to/log')
파일 sed
의 출력에 기록하여 쉘 분할로 함수에 전달합니다 "$@"
.
또는 대안으로 :
$ export $(echo PIPE FAILS | sed 's/ FAIL/=WORK/')
$ par_set $PIPE TWICE_REMOVED
$ echo "WORKS = "$WORKS
WORKS = TWICE_REMOVED
그래도 함수를 작성하려고하면 아마도 다음과 같이 보일 것입니다.
_env_eval() {
while ${2+:} false ; do
${1:+export} ${1%%["${IFS}"]*}="${2}" || :
shift 2
done
}