for 루프를 통해 다른 함수를 호출하는 함수 호출

for 루프를 통해 다른 함수를 호출하는 함수 호출

루프를 사용하여 함수를 호출 for하고 반환 값을 변수에 저장합니다. 코드를 실행하면 command not found오류가 발생합니다. 뭐가 문제 야?

#!/bin/bash

check_1()
{
    x_$1=$(check_2 $1)
}
check_2()
{
    ans=$((3+$1))
    echo $ans
}
for((i=1; i<=2;i++))
do
  check_1 $i
  tmp=x_$i
  echo ${!tmp}
done

위 스크립트를 실행하면 다음과 같은 결과를 얻습니다.

sample.sh: line 5: x_1=4: command not found
sample.sh: line 5: x_2=5: command not found

답변1

이 방법으로는 변수 이름을 정의할 수 없습니다. 다른 변수의 값을 사용하여 변수 이름을 구성하려고 하는데 x_$1=foo작동하지 않습니다. 더 좋은 방법은 배열을 사용하는 것입니다.

#!/bin/bash

check_1()
{
    x[$1]=$(check_2 "$1")

}
check_2()
{
    ans=$((3+$1))
    echo "$ans"
}
for((i=1; i<=2;i++))
do
  check_1 "$i"
  echo "${x[$i]}"
done

위의 결과는 다음과 같습니다.

$ sample.sh
4
5

답변2

Tedden이 말한 대로 해야 합니다.그의 대답, 대신 bash의 연관 배열을 사용하십시오.

그러나 당신이 주장하고 충분히 새로운 bash를 가지고 있다면 다음을 사용할 수 있습니다.이름 참조(그런데 이것은 매뉴얼 페이지에서 검색할 수 있는 마법의 단어입니다.)

i=1
declare -n tmp="foo_$i" # this is the nameref line
tmp="fooval"            # actually sets $foo_1
echo "$foo_1"           # prints fooval

함수 내부에 있는 경우 함수 로컬 변수를 가져오는 local -n대신 사용하세요.declare -n

답변3

수학만 공부하지 않는다면 제가 추천하고 싶은 유일한 것은안전하고 휴대 가능나는 매우 엄격한 테스트가 필요하지 않은 방법을 알고 있습니다.

var1=string1
export "$var1=string2"
echo "$var1"
echo "$string1"

산출

string1
string2

그러나 수학을 수행하는 중이므로 문제는 echo변수를 정의하고 동시에 현재 셸에서 평가해야 할 때 변수의 값을 하위 셸에 넣는다는 것입니다.

i=0 ; until [ $((i=$i+1)) -ge 3 ]
do  echo "\$x_$i = $((x_$i=3+$i))"
done     
echo $x_1 $x_2

산출

$x_1 = 4
$x_2 = 5
4 5

그래서 당신이 하는 일은 수학뿐입니다. 쉘 연산의 흥미로운 점은 이를 사용하여 현재 쉘의 변수를 하위 쉘 없이 두 번 안전하게 평가할 수 있다는 것입니다.

POSIX에는 이런 말이 있습니다:

산술 확장은 산술 표현식을 평가하고 해당 값을 바꾸는 메커니즘을 제공합니다. 산술 확장의 형식은 다음과 같습니다.

$((expression))

표현식은 큰따옴표로 묶인 것처럼 처리되어야 하지만 표현식 내의 큰따옴표는 특별히 처리되지 않습니다. 쉘은 매개변수 확장, 명령 대체 및 따옴표 제거를 위해 표현식의 모든 토큰을 확장해야 합니다.

아마도 더 흥미롭게도 다음과 같이 말합니다.

산술 표현식의 변수에 대한 모든 변경 사항은 매개변수 확장과 같은 산술 확장 후에 적용되어야 합니다 "${x=value}".

쉘 변수에 x유효한 정수 상수(선택적으로 선행 플러스 또는 마이너스 기호 포함)를 형성하는 값이 포함되어 있는 경우 산술 확장 합계는 동일한 값을 반환 "$((x))"해야 합니다 ."$(($x))"

따라서 산술 대체 컨텍스트에서 변수가 정의된 경우 해당 정의는 현재 환경에서 유지됩니다. 좋다:

echo $((x=1)); echo $x
1
1

하지만 다른 부분을 추가하면 - 특히셸은 모든 태그를 확장해야 합니다. 그리고저것"$((x))""$(($x))"동일한 값을 반환해야 합니다 .. 위의 루프가 어떻게 작동하는지 확인할 수 있습니다 until.

그래서:

$((x_ #just a string
     $i #integer value
        = #assignment operator
          3 + #addition
              $i )) #same integer value

쉘은 $i할당 연산자 앞의 문자열인 변수 쉘 토큰과 합계가 할당되는 정수 값에 대해 수행되는 추가 연산이라는 두 가지 컨텍스트에서 확장 되어야 함을 알 수 있습니다 x_$i.

배열은 편리할 수 있지만 한 가지 형식을 제외하면 이식성이 없으며 구현에 따른 혼란이 따릅니다. 또한 - 귀하가 요청한 질문에 대한 답변은 다음과 같습니다.

이것이 바로 다음 기능이 작동하는 이유입니다.

defv() {
    [ -n "${1##*[!0-9]*}" ] && # verify $1 is numeric only
    v=x_$1 &&                  # redefine caller loop var
    : $((x_$1=5+$1))           # : do nothing but expand arg
}

for v in 1 2 3 4 5             # init array
do  defv $v                    # defv() $indirection
    echo "$v = $(($v))"        # \$x_$indirection = $x_$indirection
done

산출

x_1 = 6
x_2 = 7
x_3 = 8
x_4 = 9
x_5 = 10

귀하의 기능:

check_1()
{
    check_2 x_$1 $1
}
check_2()
{
    : $(($1=3+$2))
}
for((i=1; i<=2;i++))
do
  check_1 $i
  tmp=x_$i
  echo ${!tmp}
done

산출

4
5

관련 정보