전역 확장을 위해 인용되지 않은 변수의 백슬래시

전역 확장을 위해 인용되지 않은 변수의 백슬래시

다음 6개의 파일이 제공됩니다.

$ touch  'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'

전역 확장을 위해 인용되지 않은 변수의 백슬래시파일 만 일치하시겠습니까 sec\*et?

$ v="sec\*et" ; ls $v
'sec\*et'
$ v='sec\*et' ; ls $v
'sec\*et'

이와 관련그래서 대답은, 이것POSIX 정의:

<백슬래시>는 이스케이프 문자라는 특별한 의미를 유지해야 합니다. 뒤에 다음 문자 중 하나가 올 때만 특별한 것으로 간주됩니다.

$ ` " \ <newline>

그리고배쉬 매뉴얼:

$백슬래시는 ' ', ' `', ' "', ' \' 또는 개행 문자 중 하나가 뒤에 오는 경우에만 특별한 의미를 유지합니다 . 큰따옴표 내에서 이러한 문자 중 하나 뒤에 오는 백슬래시가 제거됩니다. 특별한 의미가 없는 선행 백슬래시 문자는 변경되지 않습니다.

변수의 백슬래시(별표 앞)가 리터럴 백슬래시라는 것을 알고 있습니다.

$ v='sec\*et' ; printf '%s' "$v" | hexdump -C
00000000  73 65 63 5c 2a 65 74                              |sec\*et|
00000007

*그러나 리터럴 백슬래시 이후 와일드카드가 왜 특별한 의미를 잃는지 이해할 수 없습니다 .


내가 이해하는 세 가지:

*(A) 인용되지 않은 변수의 별표는 전역 확장에서 특별한 의미를 갖습니다. 그들은 동일합니다:

$ v='sec*et' ; ls $v
'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'
$ ls sec*et
'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'

*(B) 백슬래시 이후에는 별표가 특별한 의미를 잃습니다.

$ ls sec\*et
'sec*et'

(C) 리터럴 백슬래시로 인해 별표가 *특별한 의미를 잃을 수는 없습니다.

$ v='sec\\*et' ; ls $v
'sec\*et'  'sec\et'  'sec\ xxx et'
$ ls sec\\*et
'sec\*et'  'sec\et'  'sec\ xxx et'

내가 이해하지 못하는 것은 다음과 같습니다.

그런데 이상한 점은,별표는 특별한 의미를 잃지만 백슬래시는 삭제되지 않습니다., 이 경우:

$ v='sec\*et' ; ls $v
'sec\*et'

어떻게 보면 문자 그대로의 백슬래시 뒤에 문자 그대로의 별표가 오는 것과 같습니다.

$ ls sec\\\*et
'sec\*et'

그런데 왜? 고려하다:

  1. 따옴표 안의 특수 문자가 리터럴이 되면 (A)는 유지되지 않습니다.

  2. 별표 뒤에 백슬래시가 오기 때문에 리터럴이 되는 경우 sec*et(B)에서처럼 백슬래시를 삭제하고 file 과 일치시키지 않는 이유는 무엇입니까?


애플리케이션에서 Bracket Expression을 사용하는 것 외에 [*]glob 확장에 사용될 때 리터럴 별표와 일치하는 문자열 변수를 어떻게 정의할 수 있습니까?

$ v='sec < what what what > et' ; ls $v
'sec*et'

답변1

$ v="sec\*et"
$ v='sec\*et'

둘 중 하나는 변수를 로 설정하며 sec\*et, 변수가 값을 가져오는 방식은 와일드카드의 동작에 영향을 주지 않습니다.

sec\*etBash가 인용되지 않은 후속 확장을 처리하는 방식은 이스케이프 처리되지 않은 glob 문자가 없기 때문에 문자열이 glob으로 처리되지 않는 것 같습니다.별말씀을요. 예를 들어 트리거되지 않으며 failglob백슬래시가 제거되지 않습니다. 대신, 있는 그대로 인쇄합니다. (이것은 그 자체로 패턴 일치가 아닙니다. 해당 이름의 파일이 없더라도 문자열을 반환합니다.)

sec[*]et이는 다음과 관련이 있습니다.공.

또한 이를 사용한다면 sec\*et*glob이 되며 다음으로 시작하는 파일 이름과 일치합니다 sec*et(즉, 백슬래시 제거).

내가 아는 한 대부분의 Bash 버전은 이런 방식으로 작동합니다. 예외는 Bash 5.0입니다. 이는 sec\*etglob으로 처리되어 예를 들어 Failglob을 트리거합니다.

$ ./bash-4.4/bash    -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

$ ./bash-5.0/bash    -c 'shopt -s failglob; v="sec\*et"; echo $v'
./bash-5.0/bash: no match: sec\*et

$ ./bash-5.1.16/bash -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

$ ./bash-5.2.15/bash -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

(모든 경우에 모든 쉘 버전을 테스트하지는 않았습니다.)

관련 정보