이것은 구분 기호/구분 기호 /path/to/a
로 /path/to/b
사용하여 교체하려고 할 때 시도한 것입니다 .NUL
$ cat pathsList| sed -r -e 's\0/path/to/a\0/path/to/b\0g'
sed: -e expression #1, char 27: number option to `s' command may not be zero
내가 가고 싶은 곳 NUL
: NUL
및 /
허용되지 않는 유일한 문자 ext4fs
이며 경로 /
이름 구분 기호로 광범위하게 사용되었습니다. 또한 단지 데이터를 사용하기 위해 데이터를 참조하거나 역참조하는 것을 피하고 싶습니다 sed
.
NUL
구분 기호로 사용할 수 없는 경우 데이터를 인용하고 분리하는 것보다 더 나은 해결 방법이 있습니다.
$ sed --version
sed (GNU sed) 4.4
답변1
불행히도 s///
sed에서 명령의 구분 기호로 NUL을 사용하는 것은 불가능해 보입니다.
NUL 문자가 포함된 문자열을 생성하려는 경우 $'...'
bash 및 기타 쉘 인식 형식을 사용할 수 있으므로 다음과 같이 작동할 것이라고 생각할 수 있습니다.
sed -r -e $'s\0o\0x\0g'
그러나 Linux(및 일반적으로 Unix)에서 인수가 전달되는 방식으로 인해 NUL이 포함된 문자열을 전달하는 것이 실제로 불가능합니다. 왜냐하면 얻을 수 있는 것은 argc(인수의 수)와 argv(배열)뿐이고 char *
그런 다음 NUL- 이기 때문입니다. 종료된 문자열(C 문자열)은 매개변수를 얻을 수 있는 유일한 방법입니다. 즉, 모든 sed(또는 모든 프로그램)는 전달된 내용이 $'s\0o\0x\0g'
단순한 지 "s"
(그리고 NUL인 경우 이를 문자열의 끝으로 처리해야 함) 확인합니다.
외부 파일로 sed에 전달하면 작동할 것이라고 생각했습니다. 이 경우 sed는 NUL이 포함되어 있음을 알 수 있고 전체 문자열을 길이별로 추적할 수 있기 때문에 다음을 시도했습니다.
$ cat -v script.sed
s^@o^@x^@g
s ^@
는 NUL 바이트입니다. Ctrlv000ASCII 값을 통해 문자를 입력하기 위한 vim 키 입력인 (3개의 0)을 사용하여 vim에 삽입했습니다 .
하지만 이것도 작동하지 않는 것 같습니다.
$ echo "/path/to/a/folder" | sed -r -f script.sed
sed: file script.sed line 1: delimiter character is not a single-byte character
s
흥미롭게도 이는 스크립트 파일에 하나만 있는 경우와 다릅니다. 이 경우 sed는 불평합니다 unterminated 's' command
... 그래서 문자열의 길이를 추적하는 것처럼 보이지만 여전히 NUL을 구분 기호로 사용하는 것에 대해 불만스러워 보입니다. .
소스코드를 보면 sed
이것이 의도적인 것인지 버그인지는 확실하지 않습니다. is_mb_char()
바이트가 멀티바이트 문자의 일부인지 감지하는 함수 에서 NUL 처리이와 같이:
case 0: /* Special case of mbrtowc(3): the NUL character */
/* TODO: test this */
return 1;
이 경우에는 return 1
"예, 멀티바이트 문자입니다"를 의미하지만 그렇지 않습니다.
/*
* Return zero in all other cases:
* CH is a valid single-byte character (e.g. 0x01-0x7F in UTF-8 locales);
* CH is an invalid byte in a multibyte sequence for the currentl locale,
* CH is the NUL byte.
*/
그렇다면 return 0
의도적인 것이 아닐까?
이것범죄이 코드가 도입된 컨텍스트에는 더 이상 컨텍스트가 없습니다...
이것매뉴얼 페이지mbrtowc(3)
L'\0'
나는 그것이 일종의 멀티바이트 NUL이라고 생각했다고 언급했는데 , 그래서 그들이 이런 식으로 처리하기로 결정한 것일까요?
이 정보가 여전히 도움이 되기를 바랍니다!
답변2
NUL은 파일 이름에서 찾을 수 없지만(유사한 이유로 명령 인수에서는 찾을 수 없음), .
(매우 일반적임) , ^
, *
, , 이들 모두는 명령이 표현식을 이해하는 [
정규식 에 의해 있는 그대로 이스케이프될 수 있고 있어야 합니다. 운영자 .$
\
sed
s
넌 언제나 이렇게 할 수 있어도망가다자동화된 방식으로.
NUL을 제외하고 개행 문자와 모든 멀티바이트 문자는 GNU에서 사용할 수 없습니다 sed
. 다른 구현에는 다른 제한사항이 있을 수 있습니다. POSIX는 백슬래시도 금지합니다(GNU에서는 작동하지만 sed
). 따라서 백슬래시가 아닌 이식 가능한 문자 집합의 그래픽 문자를 사용하는 것이 좋습니다.
답변3
단일 문자(바이트)를 단일 문자(바이트)로 바꾸려면 다음을 사용하십시오 tr
.
$ echo "/path/to/a/folder" | tr ao xy
/pxth/ty/x/fylder
임의 문자열의 경우 Perl을 사용할 수 있습니다.
$ echo "/path/to/a/folder" | patt=o repl=xx perl -pe 's/$ENV{patt}/$ENV{repl}/g'
/path/txx/a/fxxlder
( 명령줄 인수가 처리할 파일 이름을 의미했기 때문에 patt
환경을 전달했습니다 .)repl
perl -p
물론 이는 patt
정규식으로 처리되며 모든 항목을 포함합니다.
$ echo "/path/to/a/folder" | patt='a.' repl=x perl -pe 's/$ENV{patt}/$ENV{repl}/g'
/pxh/to/xfolder
따라서 점( \.
) 및 기타 특수 문자를 이스케이프하거나 다음을 사용해야 합니다 \Q$ENV{patt}
.
$ echo "/path/to/a/folder.txt" | patt=. repl=, perl -pe 's/\Q$ENV{patt}/$ENV{repl}/g'
/path/to/a/folder,txt
위의 두 경우(명령줄 인수 및 환경 변수)에서 운영 체제와 유틸리티 간의 인터페이스는 문자열을 C 표준 라이브러리에서 사용하는 NUL 종료 문자열로 전달합니다. 이 인터페이스는 인수에 리터럴 NUL 바이트를 삽입하는 것을 불가능하게 하며, sed -e 's\a\x\g'
sed는 리터럴 백슬래시를 s
명령의 구분 기호로 사용합니다.
답변4
@cerving의 답변은 가깝지만 tr을 사용할 필요는 없습니다.
cat pathsList| sed -z 's/\n/\x0/g'
-z
구분자 로 사용됩니다 \x0
. 이는 본질적으로 파일을 긴 문자열로 변환합니다(pathsList에 아직 파일이 포함되어 있지 않은 경우 \x0
). 따라서 파일이 사용 가능한 메모리에 비해 너무 커서는 안 됩니다.