변수의 변수를 사용하여 비교기를 설정한 다음 쉘이 각 에코에서 해당 변수를 확장하도록 합니다.

변수의 변수를 사용하여 비교기를 설정한 다음 쉘이 각 에코에서 해당 변수를 확장하도록 합니다.

이것은 내 스크립트의 일부입니다.

#!/bin/sh

n=1

echo "How many repetitions to run (0 = no limit)?"
read reps

if [ $reps = 0 ]; then
    while="true"
else
    while="[ $n -lt $((reps+1)) ]"
fi

echo "How much off-time in-between reps (in minutes)?"
read time

pwr_init

while $while; do
    echo "* Sending power pulse $n"
    pwr_normal
    t=$time
    echo "* Waiting for next power on"
    while [ $t -gt 0 ]; do
        echo "    $t min until next power on"; sleep 60
        t=$((t-1))
    done
    n=$((n+1))
done

while내가 하고 있는 첫 번째 루프를 제외하면 모든 것이 내가 원하는 방식으로 정확히 작동하고 있습니다. 변수가 호출될 때마다 $while쉘이 확장되어 첫 번째 명령문에 정의된 then 변수를 확인하기를 원합니다 if.

첫 번째 문에서 변수를 확장하는 쉘만 얻을 수 있지만 비교기가 항상 true이고 첫 번째 문 내용 중에 변수가 이미 확장되었기 때문에 증가할 때 변경되지 않기 if때문에 내가 얻는 동작입니다 .true$n$whileif

${!while}비슷한 접근 방식 과 작은따옴표와 큰따옴표의 다양한 조합을 시도했지만 운이 없었습니다. 일반적 $n is a bad number으로 또는 와 유사한 오류가 발생합니다 bad substitution.

이제 내가 생각할 수 있는 유일한 것은 더 많은 함수에 더 많은 명령문을 추가하여 if이 줄이 매번 확인되어 명령문에 반영되도록 하는 것입니다. while나는 이 작업을 수행하는 더 좋은 방법이 있다고 믿어야 합니다. 그러나 나는 그것을 알아내는 데 어려움을 겪고 있습니다(또한 온라인에서 검색할 적절한 키워드를 찾는 것도 어렵습니다).

디버깅할 때 를 사용하면 set -x비교기 문자열이 여기에 스크립트된 방식으로 올바르게 평가되고 있음을 알 수 있지만 앞서 언급했듯이 $n증가해도 자체적으로 업데이트되지는 않습니다.

이 유형에 대해 인생을 좀 더 쉽게 만들어 줄 대체 팁을 갖고 있는 사람이 있나요? 이 이상한 변수 확장 수수께끼에 대한 통찰력을 제공해 주시면 대단히 감사하겠습니다!

참고 1: pwr_initpwr_normal는 전체 스크립트의 다른 곳에서 정의된 함수입니다.

참고 2: Shebang에 주의하세요. POSIX와 호환되어야 합니다. 멋진 bash 특정 기술을 사용할 수 없습니다.

편집: 작동하는 데 필요한 것처럼 작동하게 하는 것이 생각보다 쉬웠습니다. 아래에 추가한 내용을 넣었습니다. 하지만 이런 유형의 변수 확장이 가능하다면 알면 좋을 것이기 때문에 이 질문은 열어두겠습니다.

새 스크립트의 check기능은 if다음 명령문에 포함되어 있습니다.

#!/bin/sh

n=1

echo "How many repetitions to run (0 = no limit)?"
read reps

count=$((reps+1))

check() {
    if [ $reps = 0 ]; then
        while="true"
    else
        while="[ $n -lt $count ]"
    fi
}

echo "How much off-time in-between reps (in minutes)?"
read time

pwr_init

while $while; do
    echo "* Sending power pulse $n"
    pwr_normal
    t=$time
    echo "* Waiting for next power on"
    while [ $t -gt 0 ]; do
        echo "    $t min until next power on"; sleep 60
        t=$((t-1))
    done
    n=$((n+1))
    check
done

답변1

매우 간단한 해결책:"끝없이" 실행하려면 제한을 매우 큰 숫자로 설정하면 됩니다. 32비트 정수는 최대 4294967296까지의 숫자를 보유할 수 있습니다. 부호 비트를 고려하고 반내림하면 최소한 2000000000까지 셀 수 있다고 가정할 수 있습니다. 숫자를 세는 사이에 적어도 1분 동안 잠을 자기 때문에 이것은 약 4000년 동안 가능합니다.

그러니 이렇게 하세요:

if [ "$reps" = 0 ]; then
    reps=2000000000
fi

조건을 다음과 같이 하드와이어합니다.

while [ "$n" -le "$reps" ]; do ...

(64비트 시스템을 실행한다면 더 높게 계산할 수 있습니다. 하지만 상관없습니다. 16비트 시스템을 실행한다면 아마도 다른 방식으로도 망가질 것입니다. )


간단한 솔루션:reps0보다 n작은 지 확인하는 함수를 만드세요 reps.

keep_going() {
    [ "$reps" = 0 ] && return 0
    [ "$n" -le "$reps" ] 
}

그럼 조건을 내놔

while keep_going; do ...

예, 매번 함수를 호출하고 있습니다. 아니요, 최대 1분에 한 번만 호출할 수 있으므로 중요하지 않습니다. (정말 속도에 관심이 있다면 이 작업을 위해 셸을 사용하면 안 됩니다.)


당신이 찾고 있는 솔루션:사용 eval. pair 에 대한 할당에 큰따옴표를 사용하면 while="[ $n -lt $count ]"$n모두 $count즉시 확장됩니다. 필요한 것은 할당에 작은따옴표를 사용하는 것입니다. while='[ $n -lt $count ]'그런 다음 문자열을 실행하여 eval그 안의 변수를 확장합니다.

while='[ $n -lt $count ]'
while eval "$while" ; do ...

답변2

다른 함수를 정의해 볼 수 있습니다.

if [ $reps -eq 0 ]; then
    while_test() { true; }
else
    while_test() { test $1 -lt $((reps+1)); }
fi

그 다음에

while while_test $n; do

evalPOSIX 셸에서 다음을 사용하여 변수의 조건을 처리 할 수 있습니다.

$ cond='[ $n -lt $reps ]'
$ reps=5
$ n=4
$ eval "$cond" && echo 'n < reps' || echo 'n >= reps'
n < reps
$ n=5
$ eval "$cond" && echo 'n < reps' || echo 'n >= reps'
n >= reps

변수가 조기에 확장되지 않도록 조건이 작은따옴표로 정의되었는지 확인하세요.

관련 정보