NUL로 구분된 파일에서 값 제거

NUL로 구분된 파일에서 값 제거

v파일에서 삭제하고 싶은 값의 배열이 있습니다 f. fNUL로 구분됩니다. 어떻게 진행하나요? sd사용해 봤으나쓸모 없는.

예:

나는 이 파일을 가지고 있습니다 :

# cat -v $attic
^@this is 1.
this is 2.
this is 3.
^@hi
^@blue boy

이 변수는 다음 $i과 같습니다.

# cat -v <<<"$i"
this is 1.
this is 2.
this is 3.

이 파일에서 삭제하라는 명령을 실행하고 싶은데 $i결과는 다음과 같습니다.

^@hi
^@blue boy

이것을 시도했지만 FROM="$i" perl -pi -e 's/\0\Q$ENV{FROM}\E//g' "$attic"여러 줄이 있으면 작동하지 않습니다 $i. 시도해 보았 FROM="$i" perl -pi0 -e 's/\0\Q$ENV{FROM}\E//g' "$attic"으나 아무 소용이 없었습니다.

답변1

당신이 언급했으므로 zsh다음과 같이 할 수 있습니다.

zmodload zsh/mapfile
mapfile[$attic]=${(pj:\0:)"${(0@)mapfile[$attic]}":#$i}
  • $mapfile모듈 내부에는 zsh/mapfile파일 이름을 해당 내용에 매핑하는 특수 연관 배열이 있습니다.
  • "${(0@)var}": NUL로 분할합니다 $var( @예: 내부 따옴표로 빈 요소를 유지합니다 "$@").
  • ${array:#pattern}. 패턴과 일치하는 요소를 제거합니다. 여기에 있는 내용은 문자 그대로 받아들여지므로 이를 모드로 처리 $i해야 합니다 (또는 옵션을 활성화해야 합니다).$~iglobsubst
  • ${(j:string:)array}: 배열의 요소를 로 연결합니다 string. 를 사용하여 pNUL \0로 변환하세요. ( 0위의 매개변수 확장 플래그도 작성할 수 있습니다 ps:\0:.)

다음과 같은 것을 얻을 수 있습니다 perl.

FROM=$i perl -0lni -e 'print if $_ ne $ENV{FROM}' -- "$attic"

차이점은 perl아직 NUL이 없으면 끝에 NUL이 추가된다는 것입니다(일반적인 문제 -i(링크 깨짐, 모든 메타데이터를 유지하지 않음...)와 함께).

더 가까운 내용은 다음과 같습니다.

FROM=$i perl -0777 -F'\0' -pi -e '
  $_ = join "\0", grep {$_ ne $ENV{FROM}} @F' -- "$attic"

당신의

FROM="$i" perl -pi0 -e 's/\0\Q$ENV{FROM}\E//g' "$attic"

다음과 같은 이유로 작동하지 않습니다:

  • in -pi0: (백업 파일 이름 접미사) 0로 간주되는 매개변수-i
  • 비록 당신이 그것을 썼다고 해도 -0pi그것은 perlNUL-을 처리하라고 지시하기 때문에 작동하지 않을 것입니다.종료레코드이므로 $_레코드()의 끝 부분에는 시작 부분이 아닌 NUL이 포함됩니다. 전체 입력을 포함하는 하나의 레코드로 입력을 처리하려면 -0777for를 사용합니다 .perl

답변2

입력 데이터에 따라 파일이 메모리에 들어갈 만큼 작다고 가정하면 다음이 도움이 될 수 있습니다.

$ export i
$ perl -0777 -pe 's/\Q$ENV{i}\E\n?//g' file 
hi
blue boy

전체 파일이 메모리에 들어가는 원인은 무엇입니까 -0777? perl이는 $ENV{var}내보낸 환경 변수에 액세스하는 Perl의 방법입니다. 따라서 $ENV{i}내보낸 변수의 값을 얻게 됩니다 i. 글로벌 로 s/old/new/g대체됩니다 . 패턴이 정규식으로 해석되지 않는지 확인하세요 . 마지막으로, 쉘은 명령 대체(예를 들어)의 출력을 배포할 때 변수 끝에서 개행 문자를 먹기 때문에 최종 개행 문자는 실제로 포함되지 않을 수 있습니다 .oldnew\Q\E\n?var=$(printf 'foo\n')$i

이는 하위 문자열과도 일치합니다. 따라서 파일이 포함되어 i있으면 삭제되고 남겨질 것 입니다 . 이를 원하지 않으면 다음을 사용할 수 있습니다.foofoolishfooish

perl -0777 -pe 's/\Q$ENV{i}\E(\n|\b)//g' file 

예제를 테스트하십시오( 교체 ^@\0).

$ cat -v file
^@this is 1.
this is 2.
this is 3.
^@hi
^@blue boy

$ export i="$(printf 'this is 1.\nthis is 2.\nthis is 3.\n')"

$ perl -0777 -pe 's/\Q$ENV{i}\n?\E//g' file 
hi
blue boy

물론 이것은 $i후행 줄 바꿈이 없다고 가정합니다. 하나가 있는지는 모르겠습니다. cat <<<"$i"없어도 하나 추가할 것이기 때문입니다.

쉘 배열을 사용하여 이 작업을 수행해야 하는 경우 다음을 수행할 수 있습니다.

for i in "${foo[@]}"; do 
    export i
    perl -0777 -i -pe 's/\b\Q$ENV{i}\E(\n|\b)//g' file 
done

중요한: -i위의 예를 참고하세요. 이렇게 하면 파일이 그 자리에서 편집되므로 테스트하기 전에 백업하세요.

관련 정보