는? 매개변수 확장 시 특별한 방식으로 처리됩니까?

는? 매개변수 확장 시 특별한 방식으로 처리됩니까?

git status --porcelain -b프롬프트에서 사용하기 위해 from의 출력을 구문 분석하려고 하는데 매개변수 확장을 수행할 때 이상한 동작이 발생합니다.

이 코드는 문제를 보여줍니다.

#!/bin/bash
IFS=$'\n'
touch ab
status_arr=( $(git status --porcelain -b) )
for (( i=0; i<${#status_arr[@]}; i++ )); do
    echo ${status_arr[$i]}
    echo ${status_arr[$i]:0:2}
done

깨끗한 git 디렉토리에서 실행하면 다음과 같은 결과가 나타납니다.

$ bash sandbox/statusline/issue.sh 
## master...origin/master
##
?? ab
ab

??출력의 4번째 줄에 에코가 표시될 것으로 예상하며 실제로 스크립트를 touch abc또는 로 변경하면 touch a이것이 표시됩니다.

나는 이것에 대해 매우 혼란스러워서 bash에서 분명한 것을 놓치고 있는 것 같지만 인터넷 검색으로는 유용한 것을 얻지 못합니다.

이것이 알려진 "사물"인 경우 이를 회피하거나 완전히 피할 수 있는 방법이 있습니까?

답변1

?파일 이름을 일치시키는 데 사용되는 쉘 전역 문자 입니다 . 단일 문자와 일치합니다. 따라서 이름이 인 파일이 있으므로 ab??패턴이 해당 파일과 일치합니다.

이런 일이 발생하는 이유는 매개변수 확장이아니요선두.

답변2

따옴표가 없는 변수 또는 명령 대체는 문자열로 해석되지 않고 파일 이름 와일드카드 패턴 목록으로 해석됩니다. 즉, 변수 값이나 명령 출력이 문자로 구분된 별도의 부분으로 분할됩니다 IFS(이 단계를 필드 분할이라고 함). 그런 다음 각 부분은 와일드카드 패턴으로 해석되고 패턴이 일부 파일과 일치하는 경우 , 일치하는 파일 이름 목록으로 대체됩니다. 그렇지 않으면 패턴이 변경되지 않은 상태로 유지됩니다(이 단계를 파일 이름 생성이라고 함).

예를 들어 줄 바꿈만 포함하고 패턴과 일치하는 파일이 없으므로 5 자 문자열을 포함하는 단일 요소 배열로 status_arr=( $(git status --porcelain -b) )설정합니다 . 기본값에 공백이 포함되어 있으면 2-문자열이 두 번 나타나는 2요소 배열로 설정됩니다 .status_arr?? ab'IFS?? abIFSstatus_arrab

변수 또는 명령 대체가 큰따옴표로 묶인 경우 결과 문자열은 그대로 사용됩니다. 필드 분할 및 파일 이름 생성은 따옴표가 없는 대체에만 작동합니다.

를 실행하여 파일 이름 생성을 완전히 비활성화할 수 있습니다 set -f. 이는 분할을 활용하려는 경우에 유용합니다 IFS. 대체된 출력 set -f뿐만 아니라 파일 이름 생성이 완전히 비활성화된다는 점에 유의하세요 .set -f; echo **

#!/bin/bash
IFS=$'\n'
set -f
touch ab
status_arr=( $(git status --porcelain -b) )
for (( i=0; i<${#status_arr[@]}; i++ )); do
    echo "${status_arr[$i]}"
    echo "${status_arr[$i]:0:2}"
done

(여기서 파일 이름 생성은 여전히 ​​비활성화되어 있으며 고려되는 요소는 구문에 문자를 status_arr포함할 수 없으므로 명령문에서 큰따옴표를 생략하는 것이 안전합니다. 그러나 이것은 매우 취약합니다. 실제로 배열이 생성되는 방식에 크게 의존합니다. , .의 상태 와 값은 그 이후로 변경되지 않습니다 . 변수와 명령 대체를 제외할 타당한 이유가 있고 그렇게 해도 괜찮다는 것을 알고 있지 않는 한 항상 큰따옴표를 사용하십시오.IFSechoset -fIFS

관련 정보