변수에 저장된 명령을 실행


11

변수에 명령이 저장되어 있습니다. 변수 $i에 값이 있다고 가정 해 봅시다 .

cat -nT index.php |grep 'someregex'

입력하여 위의 변수 $i를 실행하려고하면 쉘이 전체 변수를 하나의 명령으로 실행하려고 시도하기 때문에 실패합니다. 나는 또한 백틱을 사용 eval($i)하고 넣었 $i습니다.

쉘을 명령 $i처럼 실행하려면 어떻게 해야합니까? 왜 작동하지 않습니까?

$i='echo hi'; $i

작은 따옴표로 해킹해야했기 때문입니까? (당신은 그들을 중첩 할 수 없기 때문에) 현재 내 솔루션은

echo $i > /foo;  . /foo

그러나 나는 이것을 위해 파일을 만들고 싶지 않고 나중에 삭제하기 만합니다.

"작은 따옴표로 해킹했다는 것은 다음과 같습니다.

$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"

4
문제는 왜 명령이 변수에 먼저 저장됩니까? 명령을 실행할 때 옵션 인수를 변수 나 배열에 저장하는 것이 좋습니다. 가지고있는 스크립트 전체를 보여줄 수 있습니까?
slhck

답변:


18

짧은 대답 : BashAQ # 50 참조 : 변수에 명령을 넣으려고하지만 복잡한 경우는 항상 실패합니다! .

긴 대답 : bash가 명령 줄을 구문 분석하는 순서 때문입니다. 특히 변수 값을 확장하기 전에 파이프 및 리디렉션과 같은 것을 찾고 확장 된 값에서 파이프 등을 다시 찾지 않습니다. 기본적으로 변수는 구문 분석 프로세스의 중간 정도에서 대체되므로 값은 실행되기 전에 절반 만 구문 분석됩니다.

이 문제를 해결하려면 @slhck의 질문에 대답해야합니다. 명령이 변수에 처음 저장된 이유는 무엇입니까? 해결하려는 실제 문제는 무엇입니까? 실제 목표에 따라 여러 가지 가능한 솔루션이 있습니다.

  • 변수에 저장하지 말고 바로 실행하십시오. 나중에 사용하기 위해 명령을 저장하는 것은 까다 롭고 실제로 필요하지 않은 경우에는 필요하지 않습니다.

  • 변수 대신 함수를 사용하십시오. 그것이 그들이 원하는 것입니다.

    i() { cat -nT index.php |grep 'someregex'; }
    i

    이것의 가장 큰 단점은 함수를 동적으로 만들 수 없다는 것입니다. 함수에서 코드를 조건부로 포함하거나 제외 할 수는 없습니다 (함수를 실행할 때 선택되는 조건부 요소를 가질 수는 있지만).

  • 사용하십시오 eval. 예기치 않은 동작이 발생하기 쉽기 때문에 최후의 수단으로 고려해야합니다. 본질적으로 다른 전체 구문 분석 패스를 통해 명령을 실행하므로 모든 파이프 등은 완전한 의미를 갖습니다. 그러나 데이터라고 생각한 명령의 일부도 구문 분석되어 실행될 수 있음을 의미합니다. 쉘 메타 문자 (파이프, 세미콜론, 따옴표 / 아포스트로피 등)가 포함 된 파일 이름은 이상하고 때로는 위험한 영향을 줄 수 있습니다. 을 사용 eval하면 문자열을 적어도 큰 따옴표로 묶어야합니다. 그렇지 않으면 내용이 본질적으로 1.5 배 파싱되어 더 이상한 결과가 발생합니다.

    i="cat -nT index.php |grep 'someregex'"
    eval "$i"

편집 : 또 다른 표준 변수 저장 명령은 간단한 변수 대신 배열을 사용하는 것입니다. 이렇게하면 문제없이 복잡한 인수 (예 : 공백 포함)가있는 명령을 저장할 수 있지만 파이프 및 리디렉션과 같은 항목은 저장하지 않습니다. 따라서이 경우에는 접근 방식이 유용하지 않습니다.


eval방법의 경우 +1 이것은 같은 질문을하지 못하게했습니다 :). 그런 sudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-root예외가 올바르게 실행되지 않는 것과 같은 것이 있습니다.
덴 텍스

@dentex 나는 eval이것을 사용하지 말 것을 강력히 권합니다 . 잘못 되기에는 너무 많은 방법이 있습니다. 배열을 사용하는 것이 더 좋은 방법입니다. 예를 보려면 여기 , 여기여기 를 참조 하십시오 .
Gordon Davisson

제안 해 주셔서 감사합니다. 제외 목록을 rsync에 전달하기 위해 배열로 솔루션을 구현하려고합니다.
dentex

4

이것은 작동해야합니다.

a="cat -nT index.php |grep 'someregex'"
eval "$a"

조심하십시오 eval만약에 이제까지 소개하고 잠재적 인 취약점 및 예기치 않은 동작이 상황이 너무 특별한주의와 함께 사용되어야합니다.


을 사용하는 경우 여분의 이상한 효과를 피하기 위해 eval큰 따옴표 ( eval "$i")를 사용해야합니다 . 예를 들어, 이것을 사용해보십시오 a="cat -nT index.php |grep ' .* '"(즉, 정규 표현식은 두 문자 사이에 임의의 문자 시퀀스가 ​​있어야 함) 실제로 어떤 일이 발생하는지 확인하십시오. 추가 크레딧이 필요한 이유를 설명 하십시오.
Gordon Davisson

@GordonDavisson 큰 따옴표가 추가되었습니다.
jlliagre

2

변수를 선언 할 때 달러 기호를 접두사로 사용해서는 안됩니다.

이 시도:

i='echo hi'; $i

1
맞지만 OP의 질문에 대한 답변은 아닙니다.
slhck

그것은 나를 위해
정말
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.