이스케이프 후 별칭을 건너뛰는 이유는 무엇입니까?

이스케이프 후 별칭을 건너뛰는 이유는 무엇입니까?

별칭을 건너뛰는 일반적인 방법은 alias 명령 앞에 백슬래시를 추가하는 것입니다. 예를 들어,

$ alias ls='ls -l'
$ ls file
-rw-r--r-- 1 user user 70 Jul 30 14:37 file
$ \ls file
file

내 연구를 통해 , l\s, "ls", 와 같은 별칭을 건너뛰는 다른 멋진 방법을 알게 되었습니다 .l""sls''

하지만 이 동작은 어디에 문서화되어 있습니까? 즉, 이것이 왜 올바른 동작입니까? 이것POSIX 사양앞에 백슬래시가 올 때 별칭을 비활성화하는 특별한 경우에 대한 문서화된 문서는 없는 것 같습니다. 나도 못찾겠다내 쉘 매뉴얼.

이것은 스스로 대답하는 질문입니다.

답변1

핵심은 쉘 구문 규칙(섹션 2.10)을 적용하기 전에 쉘이 별칭 대체(섹션 2.3.1)를 수행한다는 것입니다. 첫 번째 단계는토큰 인식(섹션 2.3):

2.3 토큰 인식
토큰은 다음 규칙 중 하나에 따라 토큰이 분리될 때까지 입력의 현재 위치에서 시작해야 합니다.토큰을 구성하는 문자는 따옴표로 묶인 문자를 포함하여 입력의 문자와 정확히 동일합니다.

(...토큰 분리 규칙...)

토큰이 구분되면 문법 요구 사항에 따라 분류됩니다. 쉘 구문.

2.3.1 별칭 대체
토큰이 구분된 후, 문법 규칙이 적용되기 전 쉘 구문, 단순 명령으로 인식되는 명령 이름 단어의 결과 단어가 맞는지 확인해야 합니다.인용되지 않은, 유효한 별칭입니다.

굵게 표시된 부분을 보면 별칭 조회 단계에 도달할 때까지 참조가 삭제되지 않았다는 결론을 내릴 수 있습니다. (백슬래시로 이스케이프하는 것도 인용문입니다.)

그런 다음 \lsor 를 발행하면 쉘이 정확한 리터럴 이름인 또는 를 l\s가진 별칭을 찾게 됩니다 .\lsl\s그런 별명은 가능하지도 않습니다, 따라서 별칭 확장이 발생하지 않고 쉘이 문법 규칙으로 전달되며, 이 시점에서 둘 다 우리의 오랜 친구로 확인됩니다 ls. 왜냐하면 "따옴표가 없는 <백슬래시>는 후속 문자의 리터럴 값을 유지해야 합니다.”. PATH 쉘 변수가 일반 변수인 경우 /bin/ls이 옵션을 사용하지 않고 실행합니다 -l.

"ls"이는 , , , , ... 별칭을 건너뛰는 이유도 설명합니다 'ls'.l""sl''s

답변2

문서

배쉬 매뉴얼하다녹음해 보세요. 내 강조점:

각 간단한 명령의 첫 번째 단어는인용없이, 별칭이 있는지 확인하세요.

mksh 매뉴얼에서:

참조된 단어가 발견되면 별칭 확장 프로세스가 중지됩니다(...)

zsh 매뉴얼에서:

별칭 확장은 기록 확장을 제외한 다른 확장 이전에 쉘 입력에 대해 수행됩니다. 따라서 foo라는 단어에 별칭이 정의된 경우 단어의 일부를 참조하여 별칭 확장을 피할 수 있습니다 \foo. 참조 양식에 대한 별칭 정의를 방지할 수 있는 방법은 없지만 모든 참조 형식이 가능합니다 \foo.

(아무것도 아니지만 setopt posix_aliases.)

이것은 대시 매뉴얼과 ksh 매뉴얼보다 낫습니다. 대시 매뉴얼은 예약어와 별칭 이전의 참조를 설명하지만 이들 간의 상호 작용은 설명하지 않습니다. ksh 매뉴얼에는 예약어가 인용되지 않은 경우에만 인식된다고 명시되어 있지만 별칭에 대해서는 이를 언급하지 않습니다.

POSIX가 이를 어떻게 지정하는지 살펴보았습니다..

근본적인

역사적으로 나는 이것이 부분적으로는 언어 디자인 선택으로, 부분적으로는 구현을 단순화하기 위해 등장했다고 생각합니다. Bourne 쉘에는 별칭이 없지만 따옴표가 없는 경우에만 예약어를 인식하는 동작이 있습니다. 이는 파서가 단어가 예약되어 있는지 조기에 알아야 하기 때문에 의미가 있습니다. 특히, 변수나 명령 대체 결과를 예약어로 처리할 때 문제가 발생합니다. 고려하다:

if condition
then
command1
"$else_or_not_else"
command2
fi

conditionfalse이고 값이 이면 else_or_not_else실행 else되어야 합니까 command2? 이를 위해서는 파서가 확장되어야 합니다 $else_or_not_else. 그러나 코드의 이 부분은 condition거짓이므로 건너뛰었습니다! "else"를 키워드로 인식해야 하는 경우 쉘 파서는 인용은 처리하지만 대체는 처리하지 않는 모드를 가져야 하므로 복잡성이 한 단계 더 추가됩니다.

대체 항목에서 별칭을 식별하는 데에도 문제가 있습니다. 별칭은 다음과 같습니다.

alias a='command1; $command2'

별칭에는 ;파서가 고려해야 하는 명령 구분 기호가 있습니다. 변수 대체 후 별칭 확장이 발생하면 변수 대체 후 파서를 다시 호출해야 합니다. 또한 별칭을 확장할 때 변수 대체를 다시 호출해야 합니다. 따라서 대체 항목에서 별칭을 인식하지 않도록 언어 설계 및 인터프리터 구현을 단순화합니다. 다시 말하지만, 사용자가 언어를 이해하고 구현자가 해석기를 만들 수 있도록 참조와 대체를 함께 배치하는 것이 더 쉽습니다.

예약어와 별칭에 대해 동일한 규칙을 유지하는 것도 단순화하는 요소입니다.

관련 정보