여러 파일로 작업을 수행하는 일반적인 방법은 다음과 같습니다. 이에 대해 저를 비난하지 마세요.
for f in $(ls); do …
이제 공백이나 기타 이상한 문자가 포함된 파일로부터 안전하려면 다음과 같은 간단한 방법을 따르세요.
find . -type f -print0 | while IFS= read -r -d '' file; …
여기 -d ''
에 그림과 같이 ASCII NUL 설정에 대한 약어가 나와 있습니다 -d $'\0'
.
그런데 왜 그럴까? 왜 ''
그리고 $'\0'
같은가요? Bash C 루트의 빈 문자열은 항상 null로 끝나기 때문인가요?
답변1
이것man page of bash
내용은 다음과 같습니다.
-d delim
The first character of delim is used to terminate the
input line, rather than newline.
문자열은 일반적으로 null로 끝나기 때문에 빈 문자열의 첫 번째 문자는 null 바이트입니다. - 합리적이라고 생각해요. :)
출처는 다음과 같이 썼습니다.
static unsigned char delim;
[...]
case 'd':
delim = *list_optarg;
break;
빈 문자열의 경우 delim
null 바이트입니다.
답변2
bash에는 서로를 보완하는 두 가지 결함이 있습니다.
이를 작성하면 $'\0'
내부적으로 빈 문자열과 동일하게 처리됩니다. 예를 들어:
$ a=$'\0'; echo ${#a}
0
bash는 내부적으로 모든 문자열을 다음과 같이 저장하기 때문입니다.씨문자열, 그들은null로 종료됨— 널 바이트는 문자열의 끝을 표시합니다. Bash는 문자열을 첫 번째 null 바이트(문자열의 일부가 아님)까지 자동으로 자릅니다.
# a=$'foo\0bar'; echo "$a"; echo ${#a}
foo
3
-d
내장 옵션 에 문자열을 인수로 전달하면 read
bash는 문자열의 첫 번째 바이트만 살펴봅니다. 그러나 실제로 문자열이 비어 있지 않은지 확인하지는 않습니다. 내부적으로 빈 문자열은 null 바이트만 포함하는 1요소 바이트 배열로 표시됩니다. 따라서 bash는 문자열의 첫 번째 바이트를 읽는 대신 null 바이트를 읽습니다.
그런 다음 내부적으로 내장 함수 뒤에 있는 메커니즘은 read
구분 기호를 찾을 때까지 바이트 단위로 계속해서 null 바이트를 처리합니다.
다른 쉘은 다르게 동작합니다. 예를 들어 ash와 ksh는 입력을 읽을 때 null 바이트를 무시합니다. ksh를 사용하여 ksh -d ""
개행 문자가 나타날 때까지 읽습니다. 쉘은 바이너리 데이터가 아닌 텍스트와 잘 작동하도록 설계되었습니다. Zsh는 예외입니다. zsh에서는 임의의 바이트(널 바이트 포함)를 처리하는 문자열 표현을 사용하며 $'\0'
길이가 1인 문자열입니다(그러나 read -d ''
이상하게도 와 같이 동작합니다 read -d $'\0'
).