이것이 작동하는 이유:
[ -r /tmp ] && echo "tt" >/tmp/taa
cat taa
tt
하지만 다음은 그렇지 않습니다. 어떻게 이 문제를 해결하고 재사용을 위한 변수를 유지할 수 있을까요?
COMD='[ -r /tmp ] && echo "tt"'
$COMD >/tmp/taa
bash: [: missing `]
감사해요
편집: eval
작동합니다. 그러나 나는 그 이유를 이해하지 못합니다.질문, 내 것이 중복으로 표시되어 있습니다, 설명이 없습니다. 또한 &&
다음으로 시작하는 부분을 제거하면 작동하며 실제로는 다음 없이 올바른 결과를 반환합니다 eval
.
COMD='[ -r /tmp ]'
$COMD
echo $?
0
COMD='[ -r /tmpdddd ]'
$COMD
echo $?
1
답변1
당신은 생각하지 않을 것입니다 :
var='echo test && reboot'
echo $var
내보낸 test
다음 다시 시작해도 괜찮나요?
대신에 출력됩니다.echo test && reboot
이는 다음과 같은 경우에 유용합니다.
var='echo test && reboot'
$var
이제 혼란스러운 점은 대부분의 Bourne 유사 쉘에서 echo test && reboot
명령을 찾을 수 없다는 오류와 함께 실패하지 않는다는 것입니다. 대신 수정하지 않으면 $IFS
출력됩니다 test && reboot
.
이는 이러한 쉘에서 변수를 따옴표로 묶지 않으면 일종의 분할+글로브 연산자가 적용되기 때문입니다.
인용되지 않았기 때문에 $var
단어로 분할됩니다(특수 인수 기준 $IFS
): echo
, test
, &&
, reboot
, 실행할 명령은 첫 번째( echo
)에서 유래하며 모든 단어는 명령에 인수로 전달됩니다. &&
인수 입니다 echo
. 따옴표가 없는 리터럴만 해당 언어의 연산자 &&
로 이해됩니다 . C와 마찬가지로 C 언어 구문에 연산자가 포함되어 있다고 해서 두 개의 인수를 전달한다는 의미는 아닙니다 .&&
sh
var="foo, bar"; printf(var)
printf
var
,
사실, 역사를 되돌아보면 1970년대 초반 유닉스의 첫 번째 버전으로 거슬러 올라갑니다 sh
.톰슨 쉘) 거기에서 실행됩니다 reboot
. sh
당시에는 변수가 지원되지 않았지만 위치 매개변수는 있었습니다 .
다음은 PDP11 에뮬레이터에서 Unix V1을 사용하는 것입니다.
$ cat myscript
echo $1
$ sh myscript 'echo test; reboot'
echo test
No command
$ ls -l /bin/sh
total 12
88 lxrwr- 1 sys 5312 Jan 1 00:00:00 sh
reboot
(다행히 당시에는 명령이 없었기 때문에 No command
오류가 발생했습니다.)
오늘날의 기준으로는 이상하게 들릴 수도 있지만 Unix V1은 수백 킬로바이트의 메모리와 메가바이트의 저장 공간을 갖춘 시스템에서 실행되었으므로 당시에는 모든 것이 단순하게 유지되어야 했습니다. 최신 시스템(아무 작업도 수행하지 않는 명령) sh
보다 얼마나 훨씬 작은 지 확인하십시오 /bin/true
(내 시스템에서는 27KB(동적 링커 또는 링크된 동적 라이브러리 제외), 이 sh의 경우 5KB).
1970년대 후반 Unix V7에는 sh
당시에는 여전히 새로운 Bourne 쉘이 탑재되어 있었습니다. 더 발전했지만 여전히 이전 제품과의 호환성을 완전히 깨뜨리지는 않습니다. 비슷한 시기에 BSD에 등장했던 csh도 마찬가지였습니다. 이것이 아마도 Bourne 쉘의 어색한 동작의 주된 이유일 것입니다: 매개변수 확장은 여전히 단어와 와일드카드로 분할하는 것과 같은 일부 형태의 확장을 거칩니다(그러나 이전 Unix 쉘에서와 같이 sh 언어를 완전히 재해석하는 것은 아닙니다. ), Thomson 쉘과 역호환 가능.
또는 (Bourne 쉘과 유사)과 같은 일부 쉘은 결국 이 문제를 해결했지만 많은 쉘은 rc
Bourne 쉘 과의 하위 호환성을 유지합니다.fish
zsh
bash
이제 문자열을 쉘 코드로 해석하려는 경우 eval
이 명령의 목적은 다음과 같습니다.
eval "$var"
(Bourne과 같은 쉘에서 분할+글로빙을 방지하기 위해 따옴표를 참고하세요).
그러나 코드를 변수에 저장하려면 다른 언어와 같은 함수를 사용하는 것이 더 합리적입니다.
f() { echo test && reboot; }
답변2
&&
변수 확장 후에는 연산자가 인식되지 않기 때문입니다 . 따옴표도 마찬가지입니다. 유효한 경우 인쇄됩니다 "tt"
. (노력하다: cmd='echo "tt"'; $cmd
)
함수로 만드세요:
checktmp() {
[ -r /tmp ] && echo "tt"
}
checktmp
함수는 코드용이고 변수는 데이터용입니다.