Null 및 이스케이프 문자 사용/읽기/쓰기

Null 및 이스케이프 문자 사용/읽기/쓰기

'/'나는 두 문자 sum 외에는 Linux의 파일 이름에 제한이 없다는 것을 알고 있습니다 '\0'. '/'디렉토리 구분 기호이기 때문에 금지되어 있다는 것을 알고 있지만다른 이유가 있나요??

또한 내 터미널에서 \0. 그래서 나는 알고 싶다null 문자를 쓰는 올바른 방법분명히 null이 포함된 파일 이름을 허용해서는 안 되기 때문입니다.

mkdir '\0' 라는 이름의 파일을 생성합니다\0

한 가지 더 질문이 있습니다. 파일 이름에 포함하려면 $백슬래시를 사용할 수 있습니다.

mkdir \$myfile라는 이름의 파일을 생성합니다 $myfile

그러나 달러 기호를 작은따옴표와 큰따옴표로 묶어도 이 작업을 수행할 수 있습니다.

mkdir \$myfile똑같아 똑같아 mkdir '$'myfile똑같아 mkdir "$"myfile똑같아mkdir '$myfile'mkdir "$myfile"

그래서 내 질문은,작은따옴표와 큰따옴표는 백슬래시 문자를 이스케이프하는 대신 사용할 수 있나요?

$, (공백) 및 백슬래시 외에 bash에서 이스케이프해야 하는 다른 문자는 무엇입니까?

답변1

널 문자 인쇄

$'\0'최근의 많은 쉘에서는 달러 작은따옴표 형식, 16진수 형식 \x00, 유니코드 형식 또는 8진수 형식을 사용하여 \u0000널 문자를 작성할 수 있습니다 . 핵심은 명령이 백슬래시 이스케이프 문자를 처리하는 방법을 알아야 한다는 것입니다. 예를 들어, 일반적으로 옵션을 추가해야 하는 경우에는 입니다 .\U00000000'\0'echo-eprintf%b

작동하는지 확인해 봅시다:

$ echo -ne '\0'
$

그래서 아무것도 생성되지 않습니다 echo -ne ''.

$ printf '%b' '\0'
$

몇 가지 문자를 추가해 보겠습니다( printf '%b'더 강력하지만 비슷한 효과가 있으므로 지금부터 계속 사용하겠습니다 echo -ne).

$ printf '%b' a'\0'b
ab

두 글자만 인쇄됩니다.유효하지 않은가다?

$ printf '%b' a'\0'b | wc -c
3

비교해 봅시다 a''b:

$ printf '%b' a''b | wc -c
2

마지막으로, 파일을 생성하기 전에 실제로 null 문자를 인쇄했는지 확인하기 위해 인쇄된 값을 오류를 발생시키는 명령에 전달해 보겠습니다. 예 xargs:

$ printf '%b' a'\0'b | xargs echo
xargs: Warning: a NUL character occurred in the input.  It cannot be 
passed through in the argument list.  Did you mean to use the --null option?
a

a끝에만 어떻게 인쇄되는지 확인하세요 . 물론 xargs -0잘 작동합니다.

$ printf '%b' a'\0'b | xargs -0 echo
a b

null을 사용하여 파일을 생성하시겠습니까?

이제 null 문자가 포함된 파일을 만들어 보겠습니다.

$ touch $'\0'
touch: cannot touch ‘’: No such file or directory
$ mkdir $'\0'
mkdir: cannot create directory ‘’: No such file or directory

# let's try another approach - using printf in command substitution:
$ touch "$(printf '%b' '\0')"
touch: cannot touch ‘’: No such file or directory
$ mkdir "$(printf '%b' '\0')"
mkdir: cannot create directory ‘’: No such file or directory

결과는 에서와 완전히 동일합니다 touch ''.유효하지 않은일제히 무시당했습니다. 명령 대체 주위에 큰따옴표를 건너뛰면 어떻게 되나요?

$ touch $(printf '%b' '\0')
touch: missing file operand
Try 'touch --help' for more information.
$ mkdir $(printf '%b' '\0')
mkdir: missing operand
Try 'mkdir --help' for more information.

이는 매개변수가 전혀 없는 touch/의 경우와 동일합니다 . mkdir또 다른 결과는 null을 텍스트로 묶는 경우입니다.

$ touch "$(printf '%b' a'\0'b)"
$ ls
a   # in zsh
ab  # in bash

표준 출력을 로 리디렉션할 수도 있지만, $'\0'얻는 것은 모두 다른 유형의 오류뿐입니다.

답변2

작은따옴표/큰따옴표 및 백슬래시: 작은따옴표와 백슬래시의 인용 기능은 동일합니다. 공백, 탭, 줄 바꿈 ()[]*$><?|{}~&;"`^!#및 잊어버린 기타 문자가 포함된 긴 문자열을 인용하려면 작은따옴표를 사용하는 것이 훨씬 더 편리합니다. 그러나 백슬래시를 사용하면 정확히 동일한 결과를 얻을 수 있습니다( `...`단, 백슬래시() 내부의 백슬래시 오버로드에 주의하세요).

그러나 큰따옴표는 고유합니다. $큰따옴표 내에서는 확장하되 작은따옴표 내에서는 확장하지 마세요. "$foo"는 foo를 확장하지만 토큰화 및 글로벌 확장으로 인한 확장 결과를 보호합니다.

http://mywiki.wooledge.org/BashFAQ시작하기 좋은 곳일 수 있습니다. Bash 매뉴얼은 설명하는 모든 기능을 사용하는 방법, 개별적으로 작동하는 방법을 설명하는 데 많은 시간을 소비하지 않습니다.


문자 그대로 0바이트를 포함하는 문자열을 명령줄 인수나 시스템 호출로 전달하는 것은 불가능합니다. ABI(Application Binary Interface)는 명령줄 인수 및 시스템 호출에 대한 파일/경로 인수를 포함하여 모든 것(바이너리 데이터 제외)을 처리하기 위해 C 문자열을 사용하여 프로세스와 커널 간에 데이터가 전달되는 방식을 정확하게 지정합니다. C 문자열은 문자열의 끝이 0바이트로 표시되는 문자 배열입니다. 문자열의 끝이 아님을 나타내기 위해 0바이트를 "이스케이프"할 수 있는 방법은 없습니다.

비슷한 작업을 시도하면 인수 목록이 다음과 같이 처리됩니다 touch $'foo\0bar'.touch

argv[0] = "/bin/touch";
argv[1] = "foo";

메모리에서는 argv[1] = "foo\0bar\0"첫 번째 항목이 \0문자열의 끝을 표시합니다. 실제로 "foo\0bar\0"은 새 프로세스의 argv에 도달하지 않습니다. exevce(2)실행 중인 시스템 호출의 argv 배열에서는 가져오지 않습니다 touch.

널 바이트의 문자 배열/문자열을 포함하는 C 또는 Perl 프로그램을 작성하더라도 이를 시스템 호출에 전달하면 open(2)커널이 문자열을 동일하게 해석하게 됩니다. read(2)및 와 같은 임의의 데이터를 처리해야 하는 시스템 호출은 write(2)길이 인수와 버퍼에 대한 포인터를 사용합니다.


bash를 사용하면 null 바이트로 아무것도 할 수 없습니다. jimmij가 지적했듯이 문자열 리터럴을 작성하는 bash 구문은 이스케이프 시퀀스를 사용하여 처리하는 것이지만 $'string'문자열 \0리터럴 내부에 작성하는 것은 bash에서 문자열 종결자 역할을 합니다. 나는 이것이 bash가 내부적으로 문자열을 명시적인 길이가 아닌 C 문자열로 저장한다는 것을 의미한다고 생각합니다.

str=$'foo\0bar'
echo "${#str}"   # 3, showing that bash isn't even storing it in a variable.
echo "$str" | wc -c   # 4. wouldn't work even if ${#str} did: echo's cmdline would eat it
wc -c <<< $'foo\0bar'   # 4 (includes a newline)

따라서 이 구문을 사용하면 null 바이트를 어디로든 보낼 수 없습니다. 우리는 뭔가를 사용해야 합니다 tr.


그러나 bash는 . 를 포함하여 . 변환 printf에 대한 백슬래시 이스케이프를 처리 하고 이미 해당 형식 문자열에서 이러한 이스케이프를 처리합니다.\0%b\0printf

  • printf '\0'0바이트를 인쇄합니다. hexdump -C확인하려면 입력하세요 .
  • printf '%s\0%s' foo bar | hexdump -Cstdout에 씁니다 foo.bar(여기서 .는 NUL 바이트임). 작은 따옴표나 큰 따옴표 안의 내용 은 \0자체적으로 확장되지 않습니다. $'\0'따옴표로만 확장할 수 있습니다.앞으로printf를 사용하면 터미네이터 역할을 하게 됩니다.
  • printf '%b' 'foo\0bar'동일한 작업을 수행하지만 더 복잡합니다.

답변3

아시다시피 $var이는 설명 변수로 이어집니다. 다양한 옵션은 다양한 이유로 작동합니다.

  • escape( \$var): 다음 문자를 쉘 기능 문자로 해석하지 않습니다. 그러나 어떤 경우에는 특별한 의미가 부여됩니다(예: \n어떤 경우에는 줄 바꿈에 사용됨).
  • 작은 따옴표( '$var'): 작은 따옴표 안의 모든 내용은 엄밀히 말하면 그 안에 포함된 문자열입니다.
  • $( ) 분리 "$"var: 싱글은 $해석되지 않으며, 큰따옴표로 묶으면 부분과 분리되어 var해석이 발생하지 않습니다.
  • 큰따옴표( "$var"): 실제로 변수가 해석되도록 허용합니다 var. mkdir "$var"작동하지 않으며 다른 변수와 동일하지 않습니다! 다시 확인 해주세요! 그러나 따옴표 안에 포함된 모든 항목은 단일 문자열로 처리됩니다. 이름에 공백이 포함된 파일 생성과 같이 파일 이름에 특수 문자가 포함된 경우 특히 유용합니다. touch "a b"-> a b단일 파일 생성/업데이트, touch a b-> 두 개의 a파일 생성/업데이트 b.

다른 특수 연산자로는 리디렉션 및 "heres" > >> < << <<<, 프로세스 연산자 & |, 부울 연산자, || &&명령 구분 기호 ;및 괄호로 그룹화 ( ), 때로는 -표준 입력 또는 명령 옵션에 대해 구분되거나 첫 번째 문자로 표시됩니다. 또한 우리가 사용한 테스트 명령 [과 인용문이 있을 ' "뿐만 아니라 !이전 명령을 호출하기 위한 느낌표나 해시된 주석을 사용하고 여러 문자와 단일 문자에 대한 #와일드카드 별표 *와 물음표도 있습니다. ?또한 현재 디렉토리와 상위 디렉토리는 ...이고 홈 디렉토리는 로 설정되어 있습니다 ~/. 즉, 문자 ; & | > < - [ \ ' " ( ) # * ! ? . ~ ^ { }, `, 개행 문자, 공백, 탭(및 단일 바이트 로케일의 기타 공백 문자)을 두 번 살펴봐야 하지만 이러한 문자가 모두 동일한 수준에서 "위험"하지는 않습니다. 너무 많기 때문에 잊지 않았으면 좋겠습니다.

답변4

파일 이름에는 '/'디렉터리 구분 기호이므로 사용이 금지됩니다. 이것이 유일한 이유입니다. 파일 시스템을 수동으로 편집하는 경우 '/'이라는 파일을 만들 수도 있습니다(많은 작업을 수행할 수 없으므로 권장되지 않음).

관련 시스템 호출은 C 언어 문자열 전달 규칙을 사용하고 NUL은 해당 문자열의 종결자이므로 NUL 문자를 파일 이름의 일부로 사용할 수 없습니다. 따라서 이름의 일부로 해석될 수 없습니다.

라는 이름의 파일을 생성하는 것은 \0NUL을 포함하는 파일을 생성하는 것과 동일하지 않습니다. 전자는 '\'두 문자 sum 을 포함하는 파일 이름 입니다 '0'.

관련 정보