eval로 실행할 때 이 간접 명령에 어떤 문제가 있나요?
#!/bin/bash
OS=AIX
host=myhost
CMD_AIX="(o=\`host \"$host\" \`)"
CMD=\$CMD_$OS
echo $CMD
eval echo $CMD
eval "$CMD"
산출:
$ myscript.sh
$CMD_AIX
(o=`host "myhost" `)
myscript.sh: line 12: (o=`host: command not found
편집 - 참고:SCO, AIX 및 Linux가 혼합되어 있으며 각각 32비트 및 64비트 변형을 포함하여 여러 버전이 있는 약 40대의 서버로 구성된 매우 이질적인 구조를 가지고 있습니다. SCO 및 AIX는 업데이트할 수 없습니다. Bash 및 Korn 셸은 모든 서버에서 공통적이지만 bash 버전 3(SCO에서는)으로 제한되고 Ksh에는 약간의 차이점이 있으므로 v3에서 연관 배열을 지원하지 않는 bash를 선호합니다(업데이트할 수 없습니다. 내 범위를 벗어나면 이러한 서버는 몇 달 내에 AIX 7 및 Linux로 교체되기 시작할 것입니다.
이미 sh 및 bsh 기반의 일부 스크립트를 포함하여 유지 관리해야 할 대규모 시스템이 있습니다. 지금은 다시 빌드하지도 않고 다시 빌드할 수도 없습니다. 교체가 끝날 때까지 몇 달 동안 헤더 유지 관리만 하면 됩니다.
이러한 스크립트에 사용된 방법은 일부 스크립트를 생성하는 대규모 솔루션에 주로 분산되어 있으며 처음부터 변경할 수는 없습니다.
위의 샘플 코드는 채택된 코드 조각일 뿐 실제 코드는 아닙니다. 논리에 대해 생각하지 말고 간접 참조(평가)에 대해서만 생각하십시오.
해결책:아주 효과적인 솔루션을 얻었습니다링크 평가, 좋다:
torun=`eval $CMD`
output=`eval torun`
답변1
내 생각에 당신이 하고 있는 일의 문제는 그것이 아무런 의미가 없다는 것입니다. 공격하려는 의도는 없지만 내 요점은 당신이 그것이 무엇을 하는지에 대해 잘못된 생각을 가지고 있다고 생각한다는 것입니다 eval
. 명령을 실행하기 위해 이를 사용하려는 것 같습니다. 이것은 기본 쉘 기능이며 쉘이 마지막 확장을 새 명령으로 해석하려고 시도할 필요가 없습니다. 이것이 바로 그 것입니다 eval
.
모든 인용문을 작성하는 방법은 어떤 것도 두 번 평가되지 않도록 보호하는 것입니다. 아니면 오히려 첫 번째 수준을 보호하고 있습니다.완전히- 그래서 두 번째 패스까지는 아무 일도 일어나지 않습니다. 이 모든 것의 문제는 당신도 그럴 수 있다는 것입니다.아니요두 번째 평가 실시(및 두 번째 수준의 따옴표)별말씀을요.
$OS
- 값을 기반으로 일부 명령을 실행 하려는 것 같습니다 .아마도...?음, 이것은 셸에서 가장 접근하기 쉬운 API 기능 중 하나입니다.
예를 들어:
OS=AIX
host=myhost
_cmd_AIX() { host "$host"; }
_cmd_WIN() { exit "$((LOSE=1))"; }
보시다시피, 참조된 정의된 함수를 실행할 수 있습니다. 해당 명령 이름은 확장의 결과로 발생하더라도 의미를 갖기 위해 특별한 두 번째 해석기가 필요하지 않습니다. 단지 명령 위치에 있어야합니다. 심지어 이런 방식으로 인수를 받아들일 수도 있으므로 원하는 $host
대로 인수를 전달할 수 있습니다. $1
그냥 이렇게 부르면 됩니다:
"_cmd_$OS"
var가 $OS
확장되고 AIX
결과 명령 단어는 _cmd_AIX
이름이 전체적으로 표시되고 명령 위치에서 적절하게 구분된 쉘 단어가 있는 미리 정의된 쉘 함수이므로 실행됩니다. 그게 다야. 비틀 필요가 없습니다. 자체 배열도 함께 제공됩니다.
$OS
다른 동작에 대해 다른 유효한 접미사를 사용하여 이름을 자유롭게 재정의하세요.
답변2
CMD
따라서 값이 string 인 변수가 있고 $CMD_AIX
변수의 값 CMD_AIX
은 string 입니다 (o=`host "myhost" `)
. CMD_AIX
쉘 명령으로 해석하여 실행하려는 값입니다 .
값을 CMD_AIX
쉘 명령으로 실행하려면 이 작업을 수행하는 쉘 명령을 구성해야 합니다. eval
목적 은 다음과 같습니다 .
eval "$CMD_AIX"
이 명령은 다시 동적으로 구성됩니다. 그래서 당신은 그것을 실행해야합니다 eval
:
dispatcher=…
eval "$dispatcher"
내부 명령이 구성되는 방식을 고려하면 다음과 같습니다.
dispatcher="eval \"\$CMD_$OS\""
eval "$dispatcher"
또는 변수를 삭제합니다.
eval "eval \"\$CMD_$OS\""
이 명령 은 의미가 없습니다. 해당 출력은 서브셸의 변수 (o=`host "myhost" `)
에 할당되며 해당 값은 서브셸 외부에서 사용할 수 없습니다. 브래킷을 제거합니다. 또한 이상한 점은 호스트 이름에 셸 특수 문자가 포함되어 있지 않기 때문에 변수 값을 큰따옴표 안에 넣는 것은 중요하지 않지만, 셸 조각을 평가할 때 변수 값을 사용하려면 이를 그대로 두어야 합니다. 확장된 상태.host
o
host \"$host\"
host
host
#!/bin/sh
OS=AIX # should probably be OS=`uname -r`
host=myhost
CMD_AIX="o=\`host \"\$host\"\`"
eval "eval \"\$CMD_$OS\""
ksh93 또는 bash ≥ 4.0을 사용하는 경우 연관 배열을 사용하여 이 스크립트를 단순화할 수 있습니다. 각 운영 체제의 코드를 다른 변수에 넣는 대신연관 배열.
#!/usr/bin/env bash
typeset -A commands
commands[AIX]="o=\`host \"\$host\"\`"
OS=AIX
host=myhost
if [ -n "${commands[$OS]}" ]; then
eval "${commands[$OS]}"
else
echo >&2 "Operating system $OS not supported"
exit 2
fi
답변3
그리고 zsh
:
$ echo $CMD
$CMD_AIX
$ echo ${(e)CMD}
(o=`host "myhost" `)
$ echo ${(e)${(e)CMD}}
(o=myhost has address 1.2.3.4)
확장 (e)
플래그는 확장되는 변수 값의 확장을 평가하는 데 사용됩니다.
ksh93 사용:
$ function CMD.get { eval ".sh.value=\"$_\""; }
$ function CMD_AIX.get { eval ".sh.value=\"$_\""; }
$ echo "$CMD_AIX"
(o=myhost has address 1.2.3.4)
$ echo "$CMD"
(o=myhost has address 1.2.3.4)
$ CMD=\$USER
$ echo "$CMD"
stephane
CMD.get
확장 시 언제든지 호출되는 규칙 함수로, $CMD
일반적으로 동적 콘텐츠가 포함된 변수를 허용하기 위해 확장이 무엇인지 정의하는 데 사용됩니다. 여기서는 큰따옴표 안의 내용을 반환하는 평가로 정의합니다(값에 큰따옴표가 포함되어 있지 않다고 가정).
다음 유형을 사용할 수도 있습니다.
typeset -T evaluating_variable=(
function get { eval ".sh.value=\"$_\""; }
)
OS=AIX host=myhost
evaluating_variable CMD_AIX='(o=`host "'$host'"`)'
evaluating_variable CMD=\$CMD_$OS
이제 쉘 스크립트에서 이 작업을 수행하는 이유는 또 다른 이야기입니다.
답변4
이로 인해 문제가 해결되었습니다.
eval `eval echo $CMD`
바꾸다:
eval "$CMD"