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'이 정의되지 않았습니다., 그러면 올바른(예상된) 출력을 얻게 됩니다. 예, 잘 들으셨습니다. 이 명령은 컴파일 시간 구성이 다르기 때문에 두 가지 다른 동작을 갖습니다.
정의 여부에 관계없이 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
는 행 단위로 실행되어 루프에서 한 행을 처리합니다. 명령의 마지막 읽기 행 이후 myalias
(위 참조) 조건은 while
false가 됩니다. myalias
세 줄의 에코로 확장되었지만 이번에는 하나의 에코만 처리됩니다. 나머지 두 개의 에코는 다음 루프에서 처리되지만... 다른 루프는 없습니다.
myalias
읽은 후에 다른 줄을 추가하면 myalias
in의 조건이 while
true로 유지되므로 다른 두 에코는 다음 루프에서 실행될 기회를 갖게 됩니다. 그 뒤의 마지막 줄은 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
,~ 해야 하다새로운 길을 택하세요.
아직도 그 이유를 설명하지 않습니다. 그러나 그것은 점점 더 실수처럼 보입니다.