질문
필드가 문자로 구분된 \n
행(구분된)으로 구성된 일부 데이터를 구문 분석하고 싶습니다 .NUL
\0
많은 Linux 명령에서는 --zero
for find
, for 또는 for와 같은 옵션을 사용하여 구분 기호를 for 로 정의함으로써 -0
이 구분 기호를 처리합니다 .xargs
\0
gawk
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
되어야 함 )는 다음과 같습니다.gawk
mawk
RS="\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
.