Najlepszy sposób na usunięcie bajtów z początku pliku?


61

Dzisiaj musiałem usunąć pierwsze 1131 bajtów z 800 MB mieszanego pliku tekstowego / binarnego, przefiltrowanego zrzutu subwersji, który włamuję do nowego repozytorium. Jak najlepiej to zrobić?

Na początek próbowałem

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

ale po pominięciu kopiuje pozostałą część pliku bajt na raz, tj. bardzo powoli. W końcu doszedłem do wniosku, że potrzebowałem 405 bajtów, aby zaokrąglić to do trzech bloków 512, które mogłem pominąć

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

które zakończyło się dość szybko, ale musiał istnieć prostszy / lepszy sposób? Czy jest inne narzędzie, o którym zapomniałem? Dzięki!


ddjest właściwym narzędziem do pracy - wygląda na to, że wymyśliłeś ładne, eleganckie rozwiązanie swojego problemu.
Justin Ethier,

Odpowiedzi:


62

Możesz przełączać opcje bs i pomijać:

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

W ten sposób operacja może skorzystać z większego bloku.

W przeciwnym razie możesz spróbować z ogonem (chociaż nie jest bezpiecznie używać go z plikami binarnymi):

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

Na koniec możesz użyć instancji 3 dd, aby napisać coś takiego:

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

gdzie pierwsze dd wypisuje standardowe wyjście filter.dump; drugi odczytuje tylko 1131 bajtów i wyrzuca je; następnie ostatni odczytuje ze swojego standardowego wejścia pozostałe bajty filter.dump i zapisuje je do trimmed.dump.


6
Dzięki! Nie wiedziałem, że dane przesyłane przez potok są przenoszone do drugiego takiego procesu - to bardzo miłe. Nie mogę uwierzyć, że nie myślałem o bs=1131 skip=1: - /
Rup

2
Większość współczesnych implementacji narzędzi powłoki działa poprawnie z plikami binarnymi (tzn. Nie mają problemów ze znakami zerowymi i nie wstawią dodatkowej nowej linii na końcu pliku). Z pewnością implementacje GNU i * BSD są bezpieczne.
Gilles

17

Nie jestem pewien, kiedy skip_byteszostał dodany, ale aby pominąć pierwsze 11 bajtów, masz:

# 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

Gdzie iflag=skip_byteskaże dd interpretować wartość skipopcji jako bajty zamiast bloków, co czyni ją prostą.


Z pewnością przewaga prędkości w przypadku dużych plików i niewielkiej ilości danych do usunięcia.
sstn

To najlepsza odpowiedź, ponieważ działa dla każdego rozmiaru bloku, np.iflag=skip_bytes skip=1234 bs=1M
phiresky

15

Możesz użyć podpowłoki i dwóch ddtakich wywołań:

$ ( 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
Dzięki - nie wiedziałem, że dane wejściowe przesyłane przez potoki przechodzą do drugiego takiego procesu, chyba jest to podpowłoka? Na pewno to zapamiętam! Dałem Marco kleszczowi, ponieważ przybył tu pierwszy, ale +1 i dziękuję za odpowiedź!
Rup

1
@Rup, tak, podpowłoka - utworzona za pomocą nawiasów - zapewnia deskryptor pliku stdin i oba wywołania dd sukcesywnie wykorzystują dane wejściowe z niego. Tak - Marco pokonał mnie o 29 sekund :)
maxschlepzig

6

Jeśli system plików i jądro Linuksa go obsługują, możesz spróbować fallocatewprowadzić zmiany w miejscu: w najlepszym przypadku nie ma żadnych danych we / wy:

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

gdzie <magic>zależy od systemu plików, wersji systemu Linux i typu pliku ( FALLOC_FL_COLLAPSE_RANGElub FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZEmoże być używany wewnętrznie ).


1
To jest moja preferowana metoda, ale jej uruchomienie w kontenerze ma swoje problemy. stackoverflow.com/questions/31155591/…
michaelcurry

3

Powinieneś użyć count=0- to proste, lseek()gdy tylko jest to możliwe.

Lubię to:

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

ddwykona lseek()deskryptor pliku wejściowego z przesunięciem 1131 bajtów, a następnie catpo prostu skopiuje wszystko, co pozostanie na wyjściu.


2

Jeszcze innym sposobem na usunięcie wiodących bajtów z pliku (bez użycia ddw ogóle) jest użycie xxdi sedlub tailodpowiednio.

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

To miłe, ale myślę, że wolę po prostu pracować z plikiem w formacie binarnym, niż konwertować go na format szesnastkowy iz niego.
Rup

2

@maxschlepzig prosi o liner online. Oto jeden w perlu. Wymaga 2 argumentów: od bajtu i długości. Plik wejściowy musi być podany jako „<”, a wyjście będzie ustawione na standardowe wyjście:

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

Jeśli długość jest większa niż plik, reszta pliku zostanie skopiowana.

W moim systemie zapewnia to 3,5 GB / s.


Myślę, że jego jedno-liniowe wyzwanie polegało na tym, abyś udowodnił, że rozwiązanie w języku skryptowym było lepsze niż jego jednowierszowe rozwiązanie powłoki. I wolę jego: jest dla mnie krótszy i jaśniejszy. Jeśli twój działa lepiej, to dlatego, że używasz większego rozmiaru bloku niż on, co można łatwo zwiększyć w jego wersji.
Rup

@Rup Niestety, ale nie. Wydaje się, że zapominasz, że ddnie gwarantuje to pełnego odczytu. Spróbuj: tak | dd bs = 1024k liczba = 10 | wc unix.stackexchange.com/questions/17295/…
Ole Tange

Również moje rozwiązanie nie odczytuje bajtów, których nie potrzebujesz (które mogą mieć długość kilku terabajtów).
Ole Tange
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.