내가 읽은 다음 내용을 확인하려고 합니다.여기:
쉘은 우리가 설명하는 모든 유형의 확장을 순서대로 수행한다는 것을 기억하는 것이 중요합니다. 이는 경로명 확장 전에 단어 확장이 수행됨을 의미합니다. 따라서 확장 경로의 결과를 반복하면 해당 결과에 대해 토큰화가 수행되지 않습니다.
나는 단어 및 경로 이름 확장 작업 순서에 관해 위의 인용문을 확인하는 매우 간단한 스크립트를 작성했습니다.
$ cat test.sh
for path in /home/john/Downloads/*.xlsx
do
echo "${path}"
done
결과
$ ./test.sh
/home/john/Downloads/CCIE-Collaboration-v3-Learning-Matrix.xlsx
/home/john/Downloads/x y.xlsx
내가 아는 한, 단어 확장은 경로 확장 전에 발생하며 이를 시연하기 위해 이와 매우 유사한 스크립트를 사용했습니다. 하지만 이 예가 어떻게 설명되는지 정말 이해가 안 가나요? 내가 아는 한, "path"는 해당 변수가 경로를 식별한 후 $path가 되는 변수입니다. 그렇다면 확장으로 간주될 단어를 볼 수 없기 때문에 도대체 단어 확장이 어디에 있을까요?
명확히 하기 위해 첫 번째 반복을 실행하면 $path는 "/home/john/Downloads/*.xlsx"를 확인할 때까지 비어 있으며, 이 시점에서는 "/home/john/Downloads/CCIE-Collaboration"으로 정의됩니다. v3-Learning-Matrix.xlsx" 왜냐하면 이것이 첫 번째 항목이기 때문입니다. 이 시점에서 $path가 정의되었으며 단어 확장을 적용할 기회가 없습니다(예: 실제 경로 이름이 정의되기 전이라고 말하는 경우) 단어 확장이 적용됨 "null"로)?
답변1
작가가 글을 쓸 때단어 확장, 그들은 페이지의 다른 곳에서는 이 용어를 사용하지 않습니다(그러나 내가 아는 한 그것은 실제로 완전히 정확합니다. POSIX 사양을 참조하십시오)여기), 그들은 "단어 분할"이라고 부르는 분할 작업을 참조하는 것 같습니다. 이는 쉘이 변수 값(보통 공백, 탭, 줄 바꿈으로 설정됨)을 기준으로 $IFS
분할되는 프로세스 입니다. 예를 들어 다음 스크립트를 고려해보세요(여기, 이는 좋은 참고 자료이므로 읽어 보시기를 적극 권장합니다):
#!/bin/sh -
printf "%d args:" "$#"
[ "$#" -eq 0 ] || printf " <%s>" "$@"
echo
스크립트는 단순히 인수를 인쇄하여 인수가 단어로 어떻게 분할되는지 보여줍니다. 다른 입력으로 실행해 보세요.
$ foo.sh apple orange "passion fruit"
3 args: <apple> <orange> <passion fruit>
여기서 문자열은 세 개의 "단어" , 및 apple orange "passion fruit"
로 구분됩니다 . 이것이 분사입니다. 따옴표가 분할되는 것을 방지하는 방법에 유의하세요 .apple
orange
passion fruit
passion fruit
이제 기사에 나와 있듯이 순서가 중요합니다. "확장"섹션을 읽으면배쉬 매뉴얼, 당신은 발견 할 것이다:
확장 순서는 중괄호 확장, 인수 및 변수 확장, 산술 확장, 명령 대체(왼쪽에서 오른쪽으로 수행)입니다.
여기서 중요한 점은 위에서 보여준 토큰화가 파일 이름(경로) 확장 전에 발생한다는 것입니다. 당신의 오해는 여기에 있습니다 :
명확히 하기 위해 첫 번째 반복을 실행하면 $path는 "/home/john/Downloads/*.xlsx"를 확인할 때까지 비어 있으며, 이 시점에서는 "/home/john/Downloads/CCIE-Collaboration"으로 정의됩니다. v3-Learning-Matrix.xlsx"는 $path가 정의되는 첫 번째 항목이기 때문입니다.
아니요, $path
이 시점에서 정의되었으며 /home/john/Downloads/CCIE-Collaboration-v3-Learning-Matrix.xlsx
루프 내부에서 확장되지 않고 루프가 시작되기 전에 확장됩니다. 우리는 현재 가지고 있는 것과 약간 다른 스크립트를 사용하여 토큰화와 경로 이름 확장이라는 두 가지를 구분할 수 있습니다.
#!/bin/bash
words="x y.xlsx *.xlsx"
for word in $words; do
echo "word is '$word'"
done
다음이 포함된 디렉터리에서 스크립트를 시도해 보세요.
$ ls -1
CCIE-Collaboration-v3-Learning-Matrix.xlsx
'x y.xlsx'
출력은 다음과 같습니다
$ foo.sh
word is 'x'
word is 'y.xlsx'
word is 'CCIE-Collaboration-v3-Learning-Matrix.xlsx'
word is 'x y.xlsx'
그래서 무슨 일이 일어났나요?
변수
$words
는나뉘다단어로 변환된 값입니다$IFS
. 결과는z
,y.xlsx
및 3개의 단어입니다*.xlsx
.다음으로 세 단어 각각은 경로 확장을 거친다. 이는 경로로 확장될 수 없고 대신 합계가 되므로 그대로 유지
x
되며 변경되지 않습니다 .y.xlsx
*.xlsx
x y.xlsx
CCIE-Collaboration-v3-Learning-Matrix.xlsx
저자가 말하려는 요점은 쉘이 and *.xlsx
로 확장될 때 x y.xlsx
이미 단어 분리가 발생했기 때문에 CCIE-Collaboration-v3-Learning-Matrix.xlsx
더 이상 단어 분리가 발생하지 않으며 x y.xlsx
공백이 포함되어 있음에도 불구하고 여전히 단일 단어로 처리된다는 것입니다.
혼란스러워서 이 답변의 첫 번째 버전이 잘못되었습니다.토큰화분사로.
답변2
나는 그들이 설명하려는 것은 쉘이 and ("경로 이름 확장") /home/john/Downloads/*.xlsx
으로 확장된 후에 그것을 다시 , and ("단어 분할" 로 분할하려고 시도하지 않는다는 것입니다 ./home/john/Downloads/CCIE-Collaboration-v3-Learning-Matrix.xlsx
/home/john/Downloads/x y.xlsx
/home/john/Downloads/CCIE-Collaboration-v3-Learning-Matrix.xlsx
/home/john/Downloads/x
y.xlsx
아니요"단어 확장"). 이 모든 for
일은 루프가 변수에 값을 할당하기 전에 발생합니다. 따라서 경로 이름 확장 결과에 대해 토큰화를 수행한다면 루프는 우리가 볼 수 있는 3개 값 대신 2개 값에 대해서만 반복하게 됩니다. 이 중 어느 것도 순환계에서 일어나는 일과 아무런 관련이 없습니다.
반면에 가 있는 경우 for i in $(echo a b c)
쉘은 명령 대체 결과를 토큰화하고 결과 루프 반복 대신 세 개의 루프 반복이 표시됩니다 for i in "$(echo a b c)"
.
답변3
이 문장"이것은 경로명 확장 전에 단어 확장이 수행된다는 것을 의미합니다."인용문에 있는 내용은 소스가 "단어 확장"이 무엇인지 정의하지 않기 때문에 의미가 없습니다. 다음 문장에서는 페이지 앞부분에서 설명한 분사를 언급하며 그 의미가 될 수 있습니다. 그래서,"단어 확장"이라는 문구를 무시하십시오. 이 경우에는 잘못되었습니다. 단순하고 간단합니다..
다음 인용문이 더 의미가 있습니다.
따라서 확장 경로의 결과를 반복하면 해당 결과에 대해 토큰화가 수행되지 않습니다.
빈 디렉터리에 두 개의 파일을 만든 다음 oneword
반복 하는 다음 상황을 고려해보세요 .two words
./*
touch 'oneword' 'two words'
i=0
for f in ./*; do
printf "%d: %s\n" "$i" "$f"
i=$(( i+1 ))
done
아래 출력은 루프가 두 개의 항목을 반복한다는 것을 보여줍니다 ./oneword
. ./two words
이는 파일 이름을 더 이상 분할하지 않고 경로 이름 확장의 직접적인 결과입니다.
0: ./oneword
1: ./two words
분사가 발생하는 경우뒤쪽에경로 이름 확장을 수행하면 두 번째 파일 이름이 로 추가로 분할되고 ./two
words
루프가 총 3번 실행됩니다. (기본값을 가정합니다 IFS
.)
위의 Q는 계속됩니다
내가 아는 한, 단어 확장은 경로 확장 전에 발생하며 이를 시연하기 위해 이와 매우 유사한 스크립트를 사용했습니다.
그러나 위에서 말했듯이 이것은 의미가 없습니다. 귀하가 인용한 출처는 "단어 확장"이 무엇을 의미하는지 정의하지 않으며 이 문구가 무엇을 의미하는지 명확하지 않습니다. 그것은 당신의 잘못이 아닙니다. 당신은 용어의 일관성을 유지할 수 없는 소스로 인해 혼란을 겪었습니다.
이제 기술적으로 말하자면,POSIX 사양모든 물결표 확장, 매개변수 확장, 명령 대체, 산술 확장, 필드 분할(종종 단어 분할이라고 함), 경로 이름/파일 이름 확장 및 인용 제거에는 "단어 확장"이라는 문구를 사용하십시오. 그러나 귀하의 출처가 해당 문구를 사용하는 맥락은 해당 정의와 맞지 않습니다. 단어 확장은 경로 확장 "이전"에 발생할 수 없습니다. 왜냐하면 단어 확장 때문입니다.포함하다경로 확장.
그렇다면 지구라는 단어의 확장은 어디서 나오는 걸까요? 확장으로 간주되는 단어가 전혀 보이지 않기 때문입니다.
다시 말하지만, 당신이 의미하는 바에 따라 다릅니다. POSIX 의미의 "단어 분리"는 거의 모든 것을 다루므로 Q의 스크립트에는 /home/john/Downloads/*.xlsx
파일 이름 에 "단어 확장"(경로 이름 확장)이 있고 "${path}"
현재 파일 이름에 "단어 확장"(매개 변수 확장)이 있습니다. 변수의 값입니다 path
. (위의 스크립트에도 산술 확장이 있습니다.)