Bash: 원격으로 실행할 때 개행 뒤의 별칭이 무시되는 이유는 무엇입니까?

Bash: 원격으로 실행할 때 개행 뒤의 별칭이 무시되는 이유는 무엇입니까?

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"이 정의되지 않은 경우, 그러면 올바른(예상) 출력을 얻을 수 있습니다. 예, 맞습니다. 컴파일 시간 구성이 다르기 때문에 명령에 두 가지 동작이 있습니다.

정의 여부는 ONESHOTBash 코드에서 완전히 다른 두 가지 경로로 이어집니다 -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명령의 마지막 줄(위 참조)의 조건은 whilefalse가 됩니다. myalias세 줄의 에코로 확장되지만 이 루프에서는 하나의 에코만 처리됩니다. 다른 두 개의 에코는 다음 루프에서 처리되지만... 다른 루프는 없습니다.

myaliasread 이후 에 한 줄을 더 추가하면 myalias조건이 whiletrue로 유지되므로 다른 두 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,~ 해야 하다새로운 회선으로 가세요.

아직도 그 이유를 설명하지 않습니다. 그러나 점점 더 버그처럼 보입니다.

관련 정보