Perl의 -0 옵션은 정확히 어떻게 작동합니까?

Perl의 -0 옵션은 정확히 어떻게 작동합니까?

에 따르면 man perlrun:

-0[octal/hexadecimal]
     specifies the input record separator ($/) as an octal or
     hexadecimal number. If there are no digits, the null character is
     the separator. 

그리고

The special value 00 will cause Perl to slurp files in paragraph
mode.  Any value 0400 or above will cause Perl to slurp files
whole, but by convention the value 0777 is the one normally used
for this purpose.

그러나 다음 입력 파일이 주어지면:

This is paragraph one

This is paragraph two.

예상치 못한 결과가 나타났습니다.

$ perl -0ne 'print; exit' file ## \0 is used, so everything is printed
This is paragraph one.

This is paragraph two.

 $ perl -00ne 'print; exit' file ## Paragraph mode, as expected
 This is paragraph one.

여태까지는 그런대로 잘됐다. 이제 이 두 가지가 단락 모드에서도 작동하는 것처럼 보이는 이유는 무엇입니까?

$ perl -000ne 'print; exit' file 
This is paragraph one.

$ perl -0000ne 'print; exit' file 
This is paragraph one.

왜 이것이 전체 파일을 다시 먹은 것 같습니까?

$ perl -00000ne 'print; exit' file 
This is paragraph one.

This is paragraph two.

추가 테스트를 통해 이들 모두가 단락 모드에서 작동하는 것으로 나타났습니다.

perl -000 
perl -0000
perl -000000
perl -0000000
perl -00000000

비록 이것들이 전체 파일을 잡아먹는 것처럼 보이지만:

perl -00000
perl -000000000

제 문제는 제가 8진수를 충분히 이해하지 못한다는 것입니다(실제로). 저는 프로그래머가 아니라 생물학자입니다. 와 ? 0000둘 다 00000000이후 두 개가 전체 파일을 먹게 될까요 >= 0400? 아니면 완전히 다른 일이 일어나고 있습니까?

답변1

8진수는 10진수와 마찬가지로 0 == 0, 0000 == 0, 0 == 000000 등입니다. 사실, 여기의 스위치는 -0상황을 다소 혼란스럽게 만들 수 있습니다. "특수 값 00"에 대한 요점은 스위치에 대해 하나의 0을 의미하고 숫자 값에 대해 더 많은 0을 추가해도 변경되지 않는다는 것을 의미한다고 가정하겠습니다. 후자이므로 동일한 결과를 얻게 됩니다...

어느 정도. 등은 000000약간 오류처럼 동작 하지만 이는 다음을 참조해야 한다는 점을 기억하세요.단일 8비트 값. 8비트의 범위는 10진수로 0~255, 8진수로 0~377입니다. 따라서 여기서는 3자리 이상의 숫자를 사용할 수 없습니다(특수 값은 모두 해당 범위를 벗어났지만 여전히 3자리 + 스위치). 다음에서 이를 추론할 수 있습니다.

16진수 표기법(-0xHHH...)을 사용하여 구분 기호를 지정할 수도 있습니다. 여기서 H는 유효한 16진수입니다.8진수 형태와는 다르게이는 모든 유니코드 문자를 지정하는 데 사용할 수 있습니다.0xFF를 넘는 값이라도.

0xFF Hex == 255 Decimal == 377 Octal == (확장) ASCII 세트의 1바이트 및 1문자 크기인 최대 8비트입니다.

답변2

perl자세한 내용을 알아보기 위해 소스 코드를 살펴보겠습니다 . 존재하다perl.c:

case '0':
    {
     I32 flags = 0;
     STRLEN numlen;

     SvREFCNT_dec(PL_rs);
     if (s[1] == 'x' && s[2]) {
          const char *e = s+=2;
          U8 *tmps;

          while (*e)
        e++;
          numlen = e - s;
          flags = PERL_SCAN_SILENT_ILLDIGIT;
          rschar = (U32)grok_hex(s, &numlen, &flags, NULL);
          if (s + numlen < e) {
           rschar = 0; /* Grandfather -0xFOO as -0 -xFOO. */
           numlen = 0;
           s--;
          }
          PL_rs = newSVpvs("");
          SvGROW(PL_rs, (STRLEN)(UNISKIP(rschar) + 1));
          tmps = (U8*)SvPVX(PL_rs);
          uvchr_to_utf8(tmps, rschar);
          SvCUR_set(PL_rs, UNISKIP(rschar));
          SvUTF8_on(PL_rs);
     }
     else {
          numlen = 4;
          rschar = (U32)grok_oct(s, &numlen, &flags, NULL);
          if (rschar & ~((U8)~0))
           PL_rs = &PL_sv_undef;
          else if (!rschar && numlen >= 2)
           PL_rs = newSVpvs("");
          else {
           char ch = (char)rschar;
           PL_rs = newSVpvn(&ch, 1);
          }
     }
     sv_setsv(get_sv("/", GV_ADD), PL_rs);
     return s + numlen;
    }

그롱크_August8진수를 나타내는 문자열을 숫자 형식으로 변환합니다. 잘못된 8진수를 입력하려고 하면 즉시 반환됩니다. 모든 4자(numlen = 4)가 유효한 값이라고 가정합니다(구현에서 for 루프를 볼 수 있습니다).숫자.c)

따라서 에서는 -00000첫 번째 항목이 perl구문 분석 -0000되고 $/으로 설정됩니다 \000. 마지막 항목이 0고려 되어 perl -0다시 $/설정됩니다 \000. 다음에서 볼 수 있습니다:

$ perl -MO=Deparse -00000777ne 'print; exit' file
BEGIN { $/ = undef; $\ = undef; }
LINE: while (defined($_ = <ARGV>)) {
    print $_;
    exit;
}
-e syntax OK

$/undef마지막으로 구문 분석된 8진수 시퀀스가 perl​​였으므로 은 으로 설정되었습니다 0777.

더 명확하게 말하자면:

$ perl -MO=Deparse -00000x1FF -ne 'print; exit' file
BEGIN { $/ = "\x{1ff}"; $\ = undef; }
LINE: while (defined($_ = <ARGV>)) {
    print $_;
    exit;
}
-e syntax OK

$/마지막 4자리 순서가 설정된 것을 확인할 수 있습니다 0x1FF.

관련 정보