0/null 구분 기호로 인해 열 명령이 중단됨

0/null 구분 기호로 인해 열 명령이 중단됨

질문

필드가 문자로 구분된 \n행(구분된)으로 구성된 일부 데이터를 구문 분석하고 싶습니다 .NUL\0

많은 Linux 명령에서는 --zerofor find, for 또는 for와 같은 옵션을 사용하여 구분 기호를 for 로 정의함으로써 -0이 구분 기호를 처리합니다 .xargs\0gawk

column구분 기호로 해석하는 방법을 이해할 수 없습니다 NUL.

다음 데이터 세트가 생성되는 경우(행 2개와 열 3개, 구분 \0):

echo -e "line1\nline2" | awk 'BEGIN {OFS="\0"} {print $1"columnA",$1"columnB",$1"columnC"}'

예상대로 다음과 같은 출력이 표시됩니다( \0구분 기호는 표시되지 않지만 각 필드는 구분됩니다).

line1columnAline1columnBline1columnC
line2columnAline2columnBline2columnC

그러나 내 열을 표시하기 위해 열을 사용하려고 하면 \0어떤 이유로 전달되었음에도 불구하고 출력에 첫 번째 열만 표시됩니다.

echo -e "line1\nline2" \ | awk 'BEGIN {FS="\0"; OFS="\0"} {print $1"columnA",$1"columnB",$1"columnC"}' | column -s '\0'
line1columnA    line2columnA

실제로 구분 기호가 제공되지 않더라도 열은 널 문자에서 중단되는 것처럼 보입니다.

echo -e "line1\nline2" \ | awk 'BEGIN {FS="\0"; OFS="\0"} {print $1"columnA",$1"columnB",$1"columnC"}' | column
line1columnA    line2columnA

질문

  • \0이것을 필드/열 구분 기호 로 사용하는 방법이 있습니까 column?
  • \0선택/추가 질문: 열이 이렇게 동작하는 이유는 무엇입니까( 관리되지 않으면 열이 완전히 무시되고 전체 행이 단일 필드로 인쇄될 것으로 예상합니다 )?
  • \0선택/보너스 질문 2: 이 열의 데이터 중 일부는 모범 사례 로 사용하고 싶은 파일 경로가 될 것입니다 . 잠재적으로 충돌할 수 있는 필드 구분 기호를 이스케이프 처리하지 않고 파일에 "임의 문자열"을 저장하는 더 나은 방법을 제안합니까?

답변1

열에서 필드/열 구분 기호로 \0을 사용하는 방법이 있습니까?

column아니요, (내가 아는 한) 두 구현 모두역사속의 BSD그리고 그 중 하나유틸리티 리눅스 패키지, 둘 다 표준 C 라이브러리의 문자열 조작 함수를 사용하여 입력 행을 구문 분석하며 이러한 함수는 문자열이 NUL로 종료된다는 가정하에 작동합니다. 즉, NUL 바이트는 다음을 의미합니다.언제나표시~의어느끈.

선택/추가 질문: 열이 이렇게 동작하는 이유는 무엇입니까(관리되지 않는 경우 \0이 완전히 무시되고 전체 행이 단일 필드로 인쇄될 것으로 예상됩니다)?

위에서 설명한 것 외에도 이 옵션 -s단어수치.그렇지 않다이스케이프 구문을 구문 분석합니다 \0(또한 \n중요하지 않음). 이것은 의미한다a 와 a를 유효한 구분 기호로 column처리하라고 말하고 있습니다.\0입력하세요.

$''이를 지원하는 많은 셸 중 하나를 사용하는 경우(예: 에서는 사용할 수 있지만 bash 에서는 사용할 수 없음 dash) 문자열 구문을 통해 이스케이프 시퀀스를 제공할 수 있습니다. 따라서 예를 들어 (<newline>을 열 구분 기호로 지정) 은 이러한 쉘 중 하나에 의해 실행되는 경우 column -s $'\n'유효합니다 .

그런데, 귀하의 기대가 무엇인지는 확실하지 않습니다 column. NUL을 구분 기호로 지원하더라도 해당 입력의 각 행을 출력 시 전체 열로 변환합니다. 어쩌면 -t행당 개별 필드를 열화하기 위해 so를 사용하고 싶습니까 ?

선택 사항/추가 질문 2: 이 열의 데이터 중 일부는 파일 경로가 될 것이며 \0을 모범 사례로 사용하고 싶습니다. 잠재적으로 충돌할 수 있는 필드 구분 기호를 이스케이프 처리하지 않고 파일에 "임의 문자열"을 저장하는 더 나은 방법을 제안합니까?

내가 아는 유일한 방법은 각 필드 앞에 길이를 붙여 텍스트나 바이너리 형식(적절하다고 생각하는 대로)으로 표현하는 것입니다. 그러나 확실히 그것들을 column.

또한 문제가 파일 경로인 경우 다음을 고려해야 합니다.아니요\n파일 이름에 대해 완전히 유효한 문자이므로 "구조" 구분 기호로 사용하십시오 .

개념 증명과 마찬가지로 예제를 기반으로 하지만 NUL을 구조체/레코드 구분 기호로 사용하고 길이가 지정된 필드를 사용합니다.(또한 멀티바이트 문자를 포함하도록 예제 문자열을 약간 수정했습니다.)

echo -e 'line1\nline2 ò' \ | LC_ALL=C awk '
    BEGIN {
        ORS="\0"
# here we just move arguments away from ARGV
# so that awk reads input from stdin
        for (i in ARGV) {
            c[i]=ARGV[i]
            delete ARGV[i]
        }
    }
    {
# first field is the line read
        printf "%4.4d%s", length, $0
# then a field for each argument
        for(i=1; i<length(c); i++)
            printf "%4.4d%s", length(c[i]), c[i]
        printf "%s", ORS
    }
' "€ column A" $'colu\nmnB' "column C"

사용논쟁awk임의의 수의 열 문자열을 전달합니다 .

그런 다음 가상의 해당 스크립트 (실제로 는 이거나 처리 awk되어야 함 )는 다음과 같습니다.gawkmawkRS="\0"

LC_ALL=C awk '
    BEGIN { RS="\0" }
    {
        nf=0; while(length) {
            field_length = substr($0, 1, 4)
            printf "field %d: \"%s\""ORS, ++nf, substr($0, 5, field_length)
            $0 = substr($0, 5+field_length)
        }
        printf "%s", ORS
    }
'

지정하는 것을 주의해 주세요동일한두 스크립트의 로케일 설정이 문자 크기와 일치합니다. 둘 다 지정해 LC_ALL=C도 괜찮습니다.

답변2

귀하의 열은 awk 명령에도 도달하지 않습니다. echo 명령 이전에도 첫 번째 0 이후의 모든 내용은 손실됩니다. 변수에 이진수 0을 저장할 수 없습니다.

var=$'zzz\x00zzz'
echo "${#var}"
3
var=$'zzz\xFFzzz'
echo "${#var}"
7

수행하려는 작업을 시작하기 전에 tr모든 0을 원하는 다른 구분 기호로 변경할 수 있습니다.

또는 쉘을 zsh.

관련 정보