간접 명령(eval)을 사용하여 변수로 출력

간접 명령(eval)을 사용하여 변수로 출력

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" `)에 할당되며 해당 값은 서브셸 외부에서 사용할 수 없습니다. 브래킷을 제거합니다. 또한 이상한 점은 호스트 이름에 셸 특수 문자가 포함되어 있지 않기 때문에 변수 값을 큰따옴표 안에 넣는 것은 중요하지 않지만, 셸 조각을 평가할 때 변수 값을 사용하려면 이를 그대로 두어야 합니다. 확장된 상태.hostohost \"$host\"hosthost

#!/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"

관련 정보