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
DanM
quelle

Antworten:

116

Versuchen Sie dd:

dd skip=102567 count=253 if=input.binary of=output.binary bs=1
Thomas Padron-McCarthy
quelle
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.

ChronoTrigger
quelle
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

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
@ 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.

Joe
quelle
2

Noch schneller

dd bs=<req len> count=1 skip=<req offset> if=input.binary of=output.binary 
Albert Burbea
quelle
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