Bash에서는 다음을 실행합니다.
alias myalias='echo foo
echo bar
echo baz'
myalias
이는 다음을 반환합니다.
foo
bar
baz
하지만:
ssh localhost "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias"
보고:
foo
왜?
답변1
내 생각에 당신은 Bash의 버그를 발견한 것 같습니다. 이 버그는 옵션에만 해당됩니다 -c
.
원격 실행은 여러 줄 별칭에 대한 문제와 관련이 없습니다. 로컬 bash에서 시도해 볼 수 있습니다. 하지만 bash 스크립트나 대화형 bash가 아닌 -c
다음과 같은 옵션을 사용하여 시도해 보세요.
bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias"
문제와 동일한 출력. 만 foo
인쇄됩니다.
올바른(예상) 출력을 얻으려면 @cuonglm이 제안한 대로 적어도 뒤에 한 줄을 더 추가해야 합니다 myalias
.
bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias
:"
왜 이런 일이 일어날까요? 도움말 뒤에 한 줄이 더 나오는 이유는 무엇입니까 myalias
?
나는 이것이 말이 안된다고 말하고 싶습니다. Bash의 어떤 문서도 이 사건을 조금도 설명하거나 언급하지 않습니다. 이런 식으로 실행되어서는 안 됩니다. 이것은 버그입니다. 코드를 읽고 나면 이 점을 확신하게 될 것입니다.
문제가 있는 첫 번째 명령으로 돌아갑니다. 이번에는 아무것도 변경하지 않고 bash를 다시 컴파일하면 됩니다."ONESHOT"이 정의되지 않은 경우, 그러면 올바른(예상) 출력을 얻을 수 있습니다. 예, 맞습니다. 컴파일 시간 구성이 다르기 때문에 명령에 두 가지 동작이 있습니다.
정의 여부는 ONESHOT
Bash 코드에서 완전히 다른 두 가지 경로로 이어집니다 -c "command"
. ONESHOT 정의를 해제하면 -c "command"
대화형 명령 및 bash 스크립트와 같은 거의 모든 bash 실행을 위한 코드 경로인 일반 코드 경로가 실행됩니다. 그러나 ONESHOT을 정의하면 -c "command"
분기를 피하여 성능을 향상시키기 위해 특별히 설계된 다른 특정 경로를 실행합니다.
이 경우 일반적이고 가장 많이 사용되는 방식은 올바른 출력을 제공할 수 있지만 특정 방식은 그렇지 않습니다. 나는 일관되지 않은 행동이 Bash 작성자가 원하는 것이 아니라고 생각합니다. 어떤 행동이 옳은가에 대해서는 일반적인 방식이 옳다고 생각하는 경향이 있습니다.
이 버그에 대한 세부 정보
다음 코드는 버그와 관련이 있습니다. 이는 buildins/evalstring.c 파일의 parse_and_execute() 함수에서 가져온 것입니다.
while (*(bash_input.location.string))
{
...
}
이 while
루프는 한 줄씩 실행되며 한 루프에서 한 줄을 처리합니다. read 이후 myalias
명령의 마지막 줄(위 참조)의 조건은 while
false가 됩니다. myalias
세 줄의 에코로 확장되지만 이 루프에서는 하나의 에코만 처리됩니다. 다른 두 개의 에코는 다음 루프에서 처리되지만... 다른 루프는 없습니다.
myalias
read 이후 에 한 줄을 더 추가하면 myalias
조건이 while
true로 유지되므로 다른 두 echo는 다음 루프에서 실행될 기회를 얻게 됩니다. 확장된 모든 에코가 처리된 후 마지막 줄이 myalias
처리됩니다 .myalias
업데이트
이 문제와 관련된 Bash 버전을 말하는 것을 잊어버렸습니다.
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
답변2
해결 방법(@cuonglm에서 영감을 얻음):
ssh localhost "shopt -s expand_aliases &>/dev/null;
alias myalias='ls
echo foo
echo bar
echo baz'
myalias &&
true"
이렇게 하면 종료 코드가 보존됩니다. 그러나 true
,~ 해야 하다새로운 회선으로 가세요.
아직도 그 이유를 설명하지 않습니다. 그러나 점점 더 버그처럼 보입니다.