Wie extrahiere ich einen einzelnen Teil von Bytes aus einer Datei?


78

Auf einem Linux-Desktop (RHEL4) möchte ich einen Bereich von Bytes (normalerweise weniger als 1000) aus einer großen Datei (> 1 Gig) extrahieren. Ich kenne den Versatz in der Datei und die Größe des Blocks.

Ich kann dazu Code schreiben, aber gibt es eine Befehlszeilenlösung?

Im Idealfall so etwas wie:

magicprogram --offset 102567 --size 253 < input.binary > output.binary

Antworten:


116

Versuchen Sie dd:

dd skip=102567 count=253 if=input.binary of=output.binary bs=1

2
Optional hinzufügen status=none, um die Ausgabe an stderr zu unterdrücken.
Kenorb

13
Hier ist ein Beispiel für die Verwendung von Hex-Offsets : dd if=in.bin bs=1 status=none skip=$((0x88)) count=$((0x80)) of=out.bin.
Kenorb

@kenorb: Ich glaube, die Hex-Syntax ist Teil von Bash, daher funktioniert sie nicht unbedingt mit anderen Shells. Ich selbst benutze tcsh (schlag mich nicht!) Und dein Beispiel funktioniert dort nicht.
Thomas Padron-McCarthy

1
Gibt es einen bestimmten Grund, warum Sie bs = 1 und count = 253 verwenden und nicht umgekehrt? Würde die größere Blockgröße den Befehl effizienter machen?
Rexford

1
@rexford: Die Sprungnummer wird ebenfalls in Blöcken angegeben und ist kein Vielfaches von 253. Da das Betriebssystem beim Lesen aus einer normalen Datei in einem Dateisystem eine eigene Pufferung durchführt, ist die Effizienz in diesem Fall nicht so niedrig wie beim Lesen von einem Gerät.
Thomas Padron-McCarthy

51

Dies ist eine alte Frage, aber ich möchte eine weitere Version des ddBefehls hinzufügen, die für große Byte-Blöcke besser geeignet ist:

dd if=input.binary of=output.binary skip=$offset count=$bytes iflag=skip_bytes,count_bytes 

wo $offsetund $bytessind Zahlen in Byteeinheiten.

Der Unterschied zu Thomas 'akzeptierter Antwort besteht darin, dass sie bs=1hier nicht angezeigt wird. bs=1Die Eingabe- und Ausgabeblockgröße beträgt 1 Byte, was es sehr langsam macht, wenn die Anzahl der zu extrahierenden Bytes groß ist.


4
Dies ist in der Tat sehr viel schneller als meine Antwort.
Thomas Padron-McCarthy

1
Funktioniert nicht auf dem Mac - iflagist ein unbekannter Operand und ohne ihn erhalten Sie einen ganzen Block.
Timmmm

1
@Timmmm GNU ddkann zur iflagUnterstützung verwendet werden ( brew install coreutils). Hinweis: Standardmäßig werden die Dienstprogramme mit einem gPräfix (z. B. gddanstelle von dd) installiert
Shakil

9

head -c + tail -c

Ich bin mir nicht sicher, wie es mit der ddEffizienz verglichen werden soll, aber es macht Spaß:

printf "123456789" | tail -c+2 | head -c3

wählt 3 Bytes ab dem 2. aus:

234

Siehe auch: https://stackoverflow.com/a/1272995/895245


@ elvis.dukaj ja, es sollte nicht anders sein. Probieren Sie es einfach mit printf '\x01\x02' > fund aus hd.
Ciro Santilli 法轮功 冠状 病 六四 事件 23

2
Viel schneller als dd mit bs = 1, danke! Bitte beachten Sie, dass Tail Bytes von 1 und nicht von 0 zählt. Außerdem wird Tail mit dem Fehlercode 1 beendet, wenn seine Ausgabe vorzeitig von head geschlossen wird. Stellen Sie sicher, dass Sie diesen Fehler ignorieren, wenn Sie "set -e" verwenden.
Proski

2

Der Befehl dd kann all dies tun. Sehen Sie sich die Such- und / oder Sprungparameter als Teil des Anrufs an.


2

Noch schneller

dd bs=<req len> count=1 skip=<req offset> if=input.binary of=output.binary 

2
Das Problem hierbei ist, dass skipin Einheiten von bs.
Arkku

Dies sollte jedoch die am besten bewertete Antwort sein. Die obige mit bs = 1 ist
absolut

Es ist ein Detail für den Testamentsvollstrecker und immer noch besser als das oben Gesagte. Es ist wahr, dass Sie Folgendes neu berechnen müssen: req_offset=$(bc <<< "$offset/$bs")und sicherstellen, dass sich ein runder Wert ergibt.
Tchakabam
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.