파일 시작 부분에서 바이트를 제거하는 가장 좋은 방법은 무엇입니까?


61

오늘은 800MB 혼합 텍스트 / 이진 파일에서 첫 번째 1131 바이트를 제거해야했습니다. 새로운 저장소를 위해 해킹중인 필터링 된 Subversion 덤프입니다. 가장 좋은 방법은 무엇입니까?

나는 시도했다

dd bs=1 skip=1131 if=filtered.dump of=trimmed.dump

그러나 건너 뛰기 후에는 파일의 나머지 부분이 한 번에 한 바이트, 즉 매우 느리게 복사됩니다. 결국 나는 이것을 건너 뛸 수있는 512의 3 블록으로 반올림하기 위해 405 바이트가 필요했습니다.

dd if=/dev/zero of=405zeros bs=1 count=405
cat 405zeros filtered.dump | dd bs=512 skip=3 of=trimmed.dump

어느 것이 상당히 빨리 완료되었지만 더 간단하고 더 나은 방법이 있었습니까? 잊어 버린 다른 도구가 있습니까? 감사!


dd작업에 적합한 도구입니다. 문제에 대한 훌륭하고 우아한 솔루션을 찾은 것 같습니다.
Justin Ethier

답변:


62

bs를 전환하고 옵션을 건너 뛸 수 있습니다.

dd bs=1131 skip=1 if=filtered.dump of=trimmed.dump

이런 식으로 작업은 더 큰 블록의 이점을 얻을 수 있습니다.

그렇지 않으면 tail로 시도 할 수 있습니다 (이진 파일과 함께 사용하는 것이 안전하지는 않지만).

tail -c +1132 filtered.dump >trimmed.dump

마지막으로 3 dd 인스턴스를 사용하여 다음과 같이 작성할 수 있습니다.

dd if=filtered.dump bs=512k | { dd bs=1131 count=1 of=/dev/null; dd bs=512k of=trimmed.dump; }

여기서 첫 번째 dd는 표준 출력을 필터링합니다. 두 번째 바이트는 1131 바이트를 읽고 버립니다. 그런 다음 마지막 입력은 표준 입력에서 나머지 bytes.filter.dump를 읽고 trimmed.dump에 씁니다.


6
감사! 파이프 입력이 이와 같은 두 번째 프로세스로 전달된다는 것을 몰랐습니다. 나는 생각하지 않았다 믿을 수 없다 bs=1131 skip=1:-/
Rup

2
대부분의 최신 셸 유틸리티 구현은 이진 파일에서 올바르게 작동합니다 (예 : null 문자에는 문제가 없으며 파일 끝에 줄 바꿈을 추가로 삽입하지 않음). 확실히 GNU 및 * BSD 구현은 안전합니다.
Gilles

17

언제 skip_bytes추가 되었는지 확실하지 않지만 처음 11 바이트를 건너 뛰려면 다음을 수행하십시오.

# echo {123456789}-abcdefgh- | 
                              dd bs=4096 skip=11 iflag=skip_bytes
-abcdefgh-
0+1 records in
0+1 records out
11 bytes (11 B) copied, 6.963e-05 s, 158 kB/s

여기서 iflag=skip_bytesdd는 skip옵션 값을 블록 대신 바이트 로 해석하도록 지시 하여 간단하게 만듭니다.


큰 파일과 적은 양의 데이터를 제거 할 경우 속도 이점이 있습니다.
sstn

이것은 모든 블록 크기에 대해 작동하기 때문에 가장 좋은 대답입니다.iflag=skip_bytes skip=1234 bs=1M
phiresky

15

다음과 dd같이 서브 쉘과 두 개의 호출을 사용할 수 있습니다 .

$ ( dd bs=1131 count=1 of=dev_null && dd bs=4K of=out.mp3 ) < 100827_MR029_LobbyControl.mp3
1+0 records in
1+0 records out
1131 bytes (1.1 kB) copied, 7.9691e-05 s, 14.2 MB/s
22433+1 records in
22433+1 records out
91886130 bytes (92 MB) copied, 0.329823 s, 279 MB/s
$ ls -l *
-rw------- 1 max users 91887261 2011-02-03 22:59 100827_MR029_LobbyControl.mp3
-rw-r--r-- 1 max users     1131 2011-02-03 23:04 dev_null
-rw-r--r-- 1 max users 91886130 2011-02-03 23:04 out.mp3
$ cat dev_null out.mp3 > orig
$ cmp 100827_MR029_LobbyControl.mp3 orig

1
감사합니다-파이프 입력이 그와 같은 두 번째 프로세스로 계속되는 것을 몰랐습니다. 나는 그것을 확실히 기억할 것이다! Marco가 처음 여기에 도착했지만 +1하고 답변에 감사드립니다.
Rup

1
@Rup, 그렇습니다. 괄호를 통해 생성 된 서브 쉘은 stdin 파일 디스크립터를 제공하며 두 dd 호출 모두 연속적으로 입력을 소비합니다. 그래 - 마르코가 29초 :)으로 날 이길
maxschlepzig

6

파일 시스템과 Linux 커널이이를 지원하는 fallocate경우 변경 사항을 적용하려는 경우 시도 할 수 있습니다. 최상의 경우 데이터 IO가 전혀 없습니다.

$ fallocate <magic> -o 0 -l 1131 inplace.dump

여기서 <magic>파일 시스템, Linux 버전 및 파일 유형 ( FALLOC_FL_COLLAPSE_RANGE또는 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE내부적으로 사용될 수 있음 ) 에 따라 다릅니다 .


1
이것이 내가 선호하는 방법이지만 컨테이너에서 이것을 실행하면 문제가 있습니다. stackoverflow.com/questions/31155591/…
마이클 카레

3

당신은 사용해야합니다 count=0- lseek()가능할 때마다 간단 합니다.

이처럼 :

{  dd bs=1131 skip=1 count=0; cat; } <filtered.dump >trimmed.dump

dd것이다 lseek()1,131 바이트 입력 파일 서술자 오프셋하고 cat단순히 출력 중 남은 복사한다.


2

그러나 (사용하지 않고 파일에서 선두 바이트를 제거하는 또 다른 방법 dd에서 모두)를 사용하는 것입니다 xxdsed또는 tail각각.

bytes=$((1131*2))

xxd -p -c 256 filtered.dump | tr -d '\n' | sed "s/^.\{0,${bytes}\}//" | xxd -r -p > trimmed.dump

bytes=$((bytes + 1)) 
xxd -p -c 256 filtered.dump | tr -d '\n' | tail -c +${bytes} | xxd -r -p > trimmed.dump

깔끔하지만 파일을 16 진수로 변환하지 않고 바이너리로 작업하는 것을 선호한다고 생각합니다.
Rup

2

@maxschlepzig는 온라인 라이너를 요청합니다. 여기에 perl이 있습니다. 바이트와 ​​길이의 두 가지 인수가 필요합니다. 입력 파일은 '<'로 제공되어야하며 출력은 stdout에 있습니다.

perl -e 'sysseek(STDIN,shift,0) || die; $left = shift;
     while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){
        $left -= $read; syswrite(STDOUT,$buf);
     }' 12345678901 19876543212 < bigfile > outfile

길이가 파일보다 크면 나머지 파일이 복사됩니다.

내 시스템에서 이것은 3.5GB / s를 제공합니다.


그의 한 줄 도전 과제는 스크립팅 언어 솔루션이 그의 한 줄 쉘 솔루션보다 낫다는 것을 입증하는 것이 었습니다. 그리고 나는 그의 것을 선호합니다 : 그것은 더 짧고 명확합니다. 당신이 더 잘 수행한다면 그것은 당신이 그의 버전에서도 쉽게 올려 진 것보다 더 큰 블록 크기를 사용하기 때문입니다.
Rup

@Rup Alas, 아니. 당신은 잊지 보인다 dd전체 읽기를 보장하지 않습니다. 예 : 예 | dd bs = 1024k count = 10 | wc unix.stackexchange.com/questions/17295/…
Ole Tange

또한 내 솔루션은 필요하지 않은 바이트를 읽지 못합니다 (몇 테라 바이트 길이 일 수 있음).
Ole Tange
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.