OSX에서 /dev/urandom을 읽을 수 없는 이유는 무엇입니까?

OSX에서 /dev/urandom을 읽을 수 없는 이유는 무엇입니까?

동료는 다음 명령을 통해 임의의 키를 만들 것을 제안했습니다.

tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

오류가 발생합니다.

tr: 잘못된 바이트 시퀀스

내 시스템에 없는 것 같아요 /dev/urandom. 이 파일을 설치하는 방법을 찾기 위해 인터넷 검색을 시도했지만 비어 있는 결과가 나왔습니다. 나는 그것을 시도했지만 locate urandom아무것도 얻지 못했습니다. (실제로 매뉴얼 페이지를 찾았지만 도움이 되지 않았습니다)

urandomMac OSX 시스템에서 어떻게 사용합니까 ? (사자)

답변1

/dev/urandom귀하가 받은 오류 메시지에 따르면 이것이 문제가 아닌 것 같습니다 . 그렇다면 비슷한 오류가 발생할 것으로 예상됩니다 no such file or directory.

귀하가 받은 오류 메시지를 검색한 결과 다음 메시지를 발견했는데, 이는 귀하의 문제와 관련이 있는 것으로 보입니다.nerdbynature.de 2010-04-11 tr-Illegal-byte-sequence (웹 아카이브의 2019-09 스냅샷)

tr기본적으로 명령 앞에 추가 LC_CTYPE=C(또는 설명 참조) 하여 로케일을 지정합니다 .LC_ALL=C

LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

답변2

tr입력을 UTF-8로 인코딩된 텍스트로 해석하려고 합니다 . 따라서 첫 번째 바이트 시퀀스가 ​​유효한 UTF-8이 아니라는 메시지를 표시하고 중단합니다. 접두사를 붙이거나 tr변수를 환경으로 내보내면 로컬 문자 집합의 아이디어가 모든 것이 불투명 바이트의 시퀀스인 C 표준으로 변경됩니다.LC_ALL=CLC_CTYPE=Ctr

그런데 \)-+명령의 순서는 의도적인 것인가요? 여기에는 *이미 포함했지만 -원하는 대로 포함되지 않은 콘텐츠도 포함됩니다. 다음과 같이 작성하는 것이 좋습니다.

LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom

답변3

다른 사람들이 지적했듯이 문제는 누락된 것이 아니라 OS X에서 작동하도록 하는 /dev/urandom방법입니다 . tr환경 변수를 사용하지 말고 대신 perl다음을 사용하십시오 tr.

perl -pe 'binmode(STDIN, ":bytes"); tr/A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+=//dc;' < /dev/urandom | head -c 32; echo

장점은 OS X, Redhat 및 Ubuntu에서 이식 가능하다는 것입니다.

(또한 파이프를 제거 xargs하고 마녀를 교체하여 echo출력 끝에 개행 문자를 얻었습니다.)

답변4

로케일의 문자 인코딩(말하는 데 사용할 수 있음 locale charmap)은 문자당 1멀티바이트입니다.

오늘날 가장 일반적인 것은 UTF-8이며 문자를 1~4바이트로 인코딩할 수 있습니다. 모든 바이트 시퀀스가 ​​UTF-8에서 유효한 문자를 형성하는 것은 아닙니다. UTF-8의 각 비ASCII 문자는 가장 높은 두 비트가 설정된 바이트로 시작하고 그 뒤에 가장 높은 비트(두 번째로 높은 비트는 아님)가 설정된 바이트 수가 옵니다.

/dev/urandom임의 바이트 스트림을 포함합니다. tr문자를 음역하므로 이러한 바이트를 문자로 디코딩해야 합니다. 해당 범위의 ASCII 문자는 한 문자에서 UTF-8로 인코딩되지만 tr모든 문자는 여전히 디코딩되어야 합니다. 예를 들어 일부 문자에 A0x41 바이트( 의 코드)가 포함 되지 않은 다른 멀티바이트 인코딩이 있습니다 A.

이 무작위 바이트 스트림에는 유효하지 않은 시퀀스가 ​​포함되어야 하기 때문입니다(예를 들어 비ASCII 문자는 0xc1보다 큰 바이트로 시작해야 하기 때문에 0x80 바이트 자체는 UTF-8에서 유효하지 않습니다(0xc0 및 0xc1은 비UTF-8에 존재하지 않음). 8자)), tr이 경우 오류가 반환됩니다.

여기서 원하는 것은 바이트 스트림을 문자당 1바이트의 인코딩에서 문자로 처리하는 것입니다. 범위에 있는 모든 문자(AZ라고 가정하면 ABCDEFGHIJKLMNOPQRSTUVWXYZ를 의미하고 Ý, 같은 문자는 아님)는 이식 가능한 문자 집합의 일부이므로 어느 것을 선택하든 상관없습니다. Ê따라서 시스템에서 지원하는 모든 문자는 동일한 코딩에 집중합니다. .

이렇게 하려면 LC_CTYPE사용되는 문자 세트와 문자 클래스에 blank포함되는 내용을 결정하는 지역화 변수를 설정해야 합니다 alpha. 그러나 AZ 범위를 정의하려면 변수 LC_COLLATE(문자열의 순서를 결정하는 변수)도 설정해야 합니다.

C일명 로케일 POSIX은 문자가 단일 바이트이고 AZ가 ABCDEFGHIJKLMNOPQRSTUVWXYZ임을 보장하는 로케일입니다. 다음을 수행할 수 있습니다.

 LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'

-(여기서는 끝으로 이동하고 , 그렇지 않으면 )-+와 같이 범위로 처리됩니다 A-Z)

LC_ALL하지만 변수는 다른 모든 LC_*변수 보다 우선한다는 점에 유의하세요 LANG. 따라서 LC_ALL이미 정의되어 있으면 위의 내용이 작동하지 않습니다. 따라서 간단히 다음을 수행할 수 있습니다.

 LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'

이는 오류 메시지의 언어와 같은 다른 사항에 영향을 주지만, 이에 관계없이 LC_CTYPE을 변경하면 이미 오류 메시지에 문제가 있을 수 있습니다(예를 들어 러시아어 또는 일본어 오류 메시지는 C 로케일의 문자 집합으로 표현할 수 없습니다).

관련 정보