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.

myalias올바른(예상) 출력을 얻으려면 @cuonglm이 제안한 대로 그 뒤에 최소한 한 줄을 추가해야 합니다 .

bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias
:"

왜 그럴까요? help 뒤에 추가 줄이 있는 이유는 무엇입니까 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는 행 단위로 실행되어 루프에서 한 행을 처리합니다. 명령의 마지막 읽기 행 이후 myalias(위 참조) 조건은 whilefalse가 됩니다. myalias세 줄의 에코로 확장되었지만 이번에는 하나의 에코만 처리됩니다. 나머지 두 개의 에코는 다음 루프에서 처리되지만... 다른 루프는 없습니다.

myalias읽은 후에 다른 줄을 추가하면 myaliasin의 조건이 whiletrue로 유지되므로 다른 두 에코는 다음 루프에서 실행될 기회를 갖게 됩니다. 그 뒤의 마지막 줄은 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,~ 해야 하다새로운 길을 택하세요.

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

관련 정보