환경을 수정하는 명령의 출력을 변수로 저장합니다.

환경을 수정하는 명령의 출력을 변수로 저장합니다.

환경을 수정하는 명령의 출력을 변수로 저장하려면 어떻게 해야 합니까?

나는 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

따라서 여기에는 환경 변화가 없습니다.

함수뿐만 아니라 명령의 출력을 변수에 저장하고 환경 변경 사항을 저장하려면 어떻게 해야 합니까?

이것이 새로운 하위 쉘을 여는 것과 그것이 문제라는 것을 알고 있지만 $(...)해결 방법이 있습니까?

답변1

Bash 4 이상을 사용하는 경우 다음을 사용할 수 있습니다.공동 프로세스:

function f () { a=3; b=4 ; echo "`date`: $a $b"; }
coproc cat
f >&${COPROC[1]}
exec {COPROC[1]}>&-
read c <&${COPROC[0]}
echo a $a
echo b $b
echo c $c

출력됩니다

a 3
b 4
c Sun Jun 29 10:08:15 NZST 2014: 3 4

coproccat주어진 명령을 실행하는 새 프로세스(여기)를 만듭니다 . PID를 배열에 저장 COPROC_PID하고 stdout/input 파일 설명자를 배열에 저장합니다 COPROC(예:pipe(2), 또는 참조여기또는여기).

여기서는 실행 중인 coprocess를 가리키는 표준 출력으로 함수를 실행한 cat다음read에서. cat단지 입력을 내보내는 것이므로 함수의 출력을 변수에 넣습니다 . 영원히 기다리지 않도록 exec {COPROC[1]}>&-파일 설명자를 닫으십시오 .cat


read한 번에 하나의 행만 필요합니다 . 이를 사용 mapfile하여 행 배열을 얻거나 파일 설명자를 사용할 수 있지만 다른 방식으로 사용하고 싶습니다.

exec {COPROC[1]}>&-현재 버전의 Bash에서 작동하지만 이전 Series 4 버전에서는 먼저 파일 설명자를 간단한 변수에 저장해야 합니다. fd=${COPROC[1]}; exec {fd}>&-변수가 설정되지 않은 경우 표준 출력이 닫힙니다.


Series 3 버전의 Bash를 사용하는 경우 다음 명령을 사용하여 동일한 효과를 얻을 수 있습니다mkfifo, 하지만 이 시점에서는 실제 파일을 사용하는 것보다 별로 좋지 않습니다.

답변2

이미 호출자와 동일한 셸에서 본문을 실행하여 및 등의 변수를 f수정할 수 있다고 생각한다면 함수를 직접 설정하는 것이 어떨까요 ? 다시 말해서:abc

$ function f () { a=3; b=4 ; c=$(echo "$(date): $a $b"); }
$ a=0; b=0; f; echo $a; echo $b; echo $c
3
4
Mon Jun 30 14:32:00 EDT 2014: 3 4

한 가지 가능한 이유는 출력 변수가 다른 위치(c1, c2 등)에서 호출될 때 다른 이름을 가져야 한다는 것일 수 있지만 c_TEMP 함수를 설정하고 호출자가 이를 수행하도록 하여 이 문제를 해결할 수 있습니다 c1=$c_TEMP.

답변3

크루거지만 한번 시도해 보세요

f > c.file
c=$(cat c.file)

(및 선택적으로 rm c.file).

답변4

모든 변수를 할당하고 동시에 출력을 작성하십시오.

f() { c= ; echo "${c:=$(date): $((a=3)) $((b=4))}" ; }

이제 이렇게 하면:

f ; echo "$a $b $c"

귀하의 출력은 다음과 같습니다

Tue Jul  1 04:58:17 PDT 2014: 3 4
3 4 Tue Jul  1 04:58:17 PDT 2014: 3 4

이는 완전히 POSIX 이식 가능한 코드입니다. 매개변수 확장이 동시 변수 할당 + 숫자로만 평가를 제한하기 때문에 처음에는 빈 문자열 c=로 설정했습니다.''(좋다 $((var=num)))또는 null 또는 존재하지 않는 값에서 - 즉, 둘 다 설정할 수 없습니다그리고변수에 값이 할당된 경우 변수는 임의의 문자열로 평가됩니다. 그래서 시도하기 전에 비어 있는지 확인합니다. 할당을 시도하기 전에 지우지 않으면 c확장 프로그램은 이전 값을 반환합니다.

증명하기 위해:

sh -c '
    c=oldval a=1
    echo ${c:=newval} $((a=a+a))
'
###OUTPUT###
oldval 2

newval아니요확장이 이기 $c때문에 할당은 인라인으로 수행되는 반면 인라인 산술 할당은 항상 발생합니다. 하지만 만약에oldval${word}$((=))$c 아니요 oldval비어 있거나 설정되지 않았습니다...

sh -c '
    c=oldval a=1
    echo ${c:=newval} $((a=a+a)) 
    c= a=$((a+a))
    echo ${c:=newval} $((a=a+a))
'
###OUTPUT###
oldval 2
newval 8

...그런 다음 newval즉시 에 할당 및 확장되었습니다 $c.

다른 모든 방법에는 일종의 2차 평가가 포함됩니다. 예를 들어, 한 지점에서 f()이름이 지정된 변수 에 의 출력을 할당하고 다른 지점에서는 . 현재 작성된 대로 호출자의 범위에 var를 설정하지 않으면 작동하지 않습니다. 그러나 다른 방법은 다음과 같습니다.namevar

f(){ fout_name= fout= set -- "${1##[0-9]*}" "${1%%*[![:alnum:]]*}"
    (: ${2:?invalid or unspecified param - name set to fout}) || set --
    export "${fout_name:=${1:-fout}}=${fout:=$(date): $((a=${a:-50}+1)) $((b=${b:-100}-4))}"
    printf %s\\n "$fout"
}

f &&
    printf %s\\n \
        "$fout_name" \
        "$fout" \
        "$a" "$b"

아래에 더 나은 형식의 예를 포함했지만 위에 표시된 대로 출력은 다음과 같습니다.

sh: line 2: 2: invalid or unspecified param - name set to fout
Wed Jul  2 02:27:07 PDT 2014: 51 96
fout
Wed Jul  2 02:27:07 PDT 2014: 51 96
51
96

또는 다른 $ENV또는 매개변수를 사용하십시오.

b=9 f myvar &&
    printf %s\\n \
        "$fout_name" \
        "$fout" \
        "$myvar" \
        "$a" "$b"

###OUTPUT###

Tue Jul  1 19:56:42 PDT 2014: 52 5
myvar
Tue Jul  1 19:56:42 PDT 2014: 52 5
Tue Jul  1 19:56:42 PDT 2014: 52 5
52
5

이중 평가의 경우 아마도 가장 까다로운 것은 변수가 따옴표를 끊지 않고 임의의 코드를 실행하지 않는지 확인하는 것입니다. 변수를 더 많이 평가할수록 더 어려워집니다. 매개변수 확장은 여기서 많은 도움이 되며 export대신 사용하는 것이 eval더 안전합니다 .

위의 예에서는 빈 문자열이 f()먼저 할당된 다음 유효한 변수 이름을 테스트하기 위해 위치 매개변수가 설정됩니다. 두 테스트가 모두 실패하면 메시지가 표시되고 기본값이 에 할당됩니다 . 그러나 테스트에 관계없이 지정한 이름은 항상 할당되고 (선택적으로) 지정한 이름은 항상 함수의 출력 값에 할당됩니다. 이를 보여주기 위해 다음과 같은 작은 루프를 작성했습니다 .$fout''stderrfout$fout_name$fout_namefout$foutfor

for v in var '' "wr;\' ong"
    do sleep 10 &&
        a=${a:+$((a*2))} f "$v" || break
    echo "${v:-'' #null}" 
    printf '#\t"$%s" = '"'%s'\n" \
        a "$a" b "$b" \
        fout_name "$fout_name" \
        fout "$fout" \
        '(eval '\''echo "$'\''"$fout_name"\")' \
            "$(eval 'echo "$'"$fout_name"\")"
 done

일부 문제를 해결하기 위해 변수 이름과 매개변수 확장을 사용합니다. 궁금한 점이 있으면 문의하세요. 저것오직여기에 이미 표시된 함수에서 동일한 몇 줄을 실행합니다. 적어도 변수는 호출 시 정의되었는지 또는 이미 설정되었는지에 따라 다르게 동작한다는 점을 언급할 가치가 $a있습니다 $b. 그럼에도 불구하고 for데이터 세트의 형식을 지정하고 제공하는 것 외에는 거의 아무것도 수행하지 않습니다 f(). 구경하다:

###OUTPUT###

Wed Jul  2 02:50:17 PDT 2014: 51 96
var
#       "$a" = '51'
#       "$b" = '96'
#       "$fout_name" = 'var'
#       "$fout" = 'Wed Jul  2 02:50:17 PDT 2014: 51 96'
#       "$(eval 'echo "$'"$fout_name"\")" = 'Wed Jul  2 02:50:17 PDT 2014: 51 96'
sh: line 2: 2: invalid or unspecified param - name set to fout
Wed Jul  2 02:50:27 PDT 2014: 103 92
'' #null
#       "$a" = '103'
#       "$b" = '92'
#       "$fout_name" = 'fout'
#       "$fout" = 'Wed Jul  2 02:50:27 PDT 2014: 103 92'
#       "$(eval 'echo "$'"$fout_name"\")" = 'Wed Jul  2 02:50:27 PDT 2014: 103 92'
sh: line 2: 2: invalid or unspecified param - name set to fout
Wed Jul  2 02:50:37 PDT 2014: 207 88
wr;\' ong
#       "$a" = '207'
#       "$b" = '88'
#       "$fout_name" = 'fout'
#       "$fout" = 'Wed Jul  2 02:50:37 PDT 2014: 207 88'
#       "$(eval 'echo "$'"$fout_name"\")" = 'Wed Jul  2 02:50:37 PDT 2014: 207 88'

관련 정보