bash 파이프에서 원시 이진 데이터를 어떻게 처리 할 수 ​​있습니까?


15

파일을 매개 변수로 사용하고 파일이 존재하는지 확인한 다음 stdin에서 나오는 모든 것을 파일에 기록하는 bash 함수가 있습니다. 순진한 솔루션은 텍스트에 적합하지만 임의의 이진 데이터에 문제가 있습니다.

echo -n '' >| "$file" #Truncate the file
while read lines
do  # Is there a better way to do this? I would like one...
    echo $lines >> "$file"
done

답변:


15

당신의 방법은 구분 기호 ( $IFS)가 읽기를 분할하는 데 사용하는 모든 공간에 쓰는 모든 것에 줄 바꿈을 추가하는 것입니다 . 개행으로 나누는 대신 모든 것을 가져 와서 전달하십시오. 위 코드 전체를 다음과 같이 줄일 수 있습니다.

 cat - > $file

자르기 비트가 필요하지 않으므로 전체 STDIN 스트림을 자르고 기록합니다.

편집 : zsh를 사용 > $file하는 경우 고양이 대신 사용할 수 있습니다 . 파일로 리디렉션하고 파일을 자르고 있지만 걸려있는 것이 있으면 STDIN을 받기를 기다리는 것이 그 시점에서 읽 힙니다. bash를 사용하여 이와 같은 작업을 수행 할 수 있다고 생각하지만 특수 모드를 설정해야합니다.


stdin 리디렉션 예제를 작동시킬 수 없지만 cat 예제를> |로 변경하십시오. (클로버 세트가 없습니다)는 매력처럼 작동합니다. 내 하루를 만들어 주셔서 감사합니다 ^. ^
David Souther

고양이없는 버전의 경우 +1 항상 쓸모없는 고양이를 피하십시오;)
rozcietrzewiacz

@rozcietrzewiacz : 나중에 생각하고 틀렸다는 것을 제외하고는 사실입니다. 이것은 쓸모없는 고양이의 사용이 아닐 수도 있습니다. 당신이 할 수있는 유일한 일은입니다 > $file. 이것은 부모 쉘 스크립트에서 stdin을 찾는 첫 번째 기능으로 만 작동합니다. 기본적으로 모든 David의 코드는 단일 문자로 축소 될 수 있지만 cat -시력을 이해하기 때문에보다 우아하고 문제가 적습니다.
Caleb

때때로 나는 catUUOC 광신자들을 성가 시게하기 위해 4 ~ 5 초를 묶습니다
Michael Mrozek

@ MichaelMrozek : 때로는 데이터 파일의 이름을 지정하기 때문에 데이터 cat사용을 주장하는 사람들은 반드시 코드를 읽으려면 정신 체조를해야합니다. 명명 된 파이프도 좋은 목표입니다.
Caleb

7

텍스트 파일을 문자 그대로 읽으려면 read다음 두 가지 방법으로 출력을 처리하는 plain을 사용하지 마십시오 .

  • read\이스케이프 문자로 해석 합니다. 이 기능 read -r을 끄 려면 사용하십시오 .
  • read$IFS; 문자의 단어로 나눕니다 . IFS이것을 끄려면 빈 문자열로 설정하십시오 .

텍스트 파일을 한 줄씩 처리하는 일반적인 관용구는

while IFS= read -r line; do 

이 관용구에 대한 설명을 참조하십시오 while IFS= read대신, 자주 사용 IFS=; while read..? .

문자열을 문자 그대로 쓰려면 echo두 가지 방법으로 문자열을 처리하는 plain을 사용하지 마십시오 .

  • 일부 쉘에서는 echo백 슬래시 이스케이프를 처리합니다. (bash에서 xpg_echo옵션의 설정 여부에 따라 다릅니다 .)
  • 일부 문자열은 옵션으로 취급됩니다 ( 예 : -n또는 -e(정확한 세트는 쉘에 따라 다름).

문자 그대로 문자열을 인쇄하는 휴대용 방법은입니다 printf. (입력 옵션이 옵션처럼 보이지 않는 한 bash에는 더 좋은 방법이 없습니다 echo.) 첫 번째 양식을 사용하여 정확한 문자열을 인쇄하고 두 번째 양식을 사용하여 줄 바꿈을 추가하십시오.

printf %s "$line"
printf '%s\n' "$line"

다음 과 같은 이유로 text 처리에만 적합합니다 .

  • 대부분의 쉘은 입력에서 널 문자를 질식시킵니다.
  • 마지막 줄을 읽었을 때 끝에 줄 바꿈이 있는지 알 수있는 방법이 없습니다. 입력이 줄 바꿈으로 끝나지 않으면 일부 오래된 쉘에서 더 큰 문제가 발생할 수 있습니다.

쉘에서 이진 데이터를 처리 할 수는 없지만 대부분의 유니스에있는 최신 버전의 유틸리티는 임의의 데이터를 처리 할 수 ​​있습니다. 모든 입력을 출력으로 전달하려면을 사용하십시오 cat. 접선에가는 것은 echo -n ''복잡하고 이식성이없는 방법으로 아무것도하지 않습니다. echo -n셸에 의존하지 않는 것처럼 좋을뿐 아니라 :더 단순하고 휴대가 간편합니다.

: >| "$file"
cat >>"$file"

또는 더 간단합니다.

cat >|"$file"

스크립트에서는 일반적 으로 기본적으로 꺼져 >|있기 때문에 사용할 필요가 없습니다 noclobber.


xpg_echo를 지적 해 주셔서 감사합니다. 실제로 코드에서 다른 곳에서 발생하고 심지어 깨닫지 못하는 문제입니다. 재 클로저, 나는 내 bashrc에서 켜는 습관이 있습니다.
David Souther

0

이것은 당신이 원하는 것을 정확하게 할 것입니다 :

( while read -r -d '' ; do
    printf %s'\0' "${REPLY}" ;
  done ;

  # When read hits EOF, it returns non-zero which exits the while loop.
  # That data still needs to be output:
  printf %s "${REPLY}"
) >> ${file}

그래도 메모리 사용량에 유의하십시오. 널로 구분 된 입력을 읽습니다.

입력에 \0 바이트 가 없으면 bash는 먼저 입력의 전체 내용을 메모리로 읽어서 출력해야합니다.

자르기 단계와 관련하여 :

echo -n '' >| "$file" #Truncate the file

훨씬 간단하고 동등한 내용은 다음과 같습니다.

> ${file}   #Truncate the file
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.