환경을 수정하는 명령의 출력을 변수로 저장하려면 어떻게 해야 합니까?
나는 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
coproc
cat
주어진 명령을 실행하는 새 프로세스(여기)를 만듭니다 . 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
수정할 수 있다고 생각한다면 함수를 직접 설정하는 것이 어떨까요 ? 다시 말해서:a
b
c
$ 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를 설정하지 않으면 작동하지 않습니다. 그러나 다른 방법은 다음과 같습니다.name
var
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
''
stderr
fout
$fout_name
$fout_name
fout
$fout
for
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'