dd: mehrere eingabedateien

13

Ich muss Blöcke aus zwei Dateien verketten:

Wenn ich ganze Dateien verketten müsste, könnte ich das einfach tun

cat file1 file2 > output

Aber ich muss zuerst 1 MB aus der ersten Datei auslassen, und ich möchte nur 10 MB aus der zweiten Datei. Klingt nach einem Job für dd.

dd if=file1 bs=1M count=99 skip=1 of=temp1
dd if=file2 bs=1M count=10 of=temp2
cat temp1 temp2 > final_output

Gibt es eine Möglichkeit, dies in einem Schritt zu tun? dh ohne dass die Zwischenergebnisse gespeichert werden müssen? Kann ich mehrere Eingabedateien in verwenden dd?

Martin Vegter
quelle

Antworten:

21

dd kann auch nach stdout schreiben.

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output
meuh
quelle
Dies ist wahrscheinlich der beste Weg. Die Ausgabedatei wird nicht geschlossen / erneut geöffnet (wie bei oflag=append conv=notrunc), sodass Dateisysteme mit verzögerter Zuweisung (wie XFS) mit der geringsten Wahrscheinlichkeit entscheiden, dass das Schreiben der Datei abgeschlossen ist, wenn noch mehr zu tun ist.
Peter Cordes
@PeterCordes, das ist ein guter Punkt, aber solange ddnicht darum gebeten wird, syncsollte die verzögerte Zuweisung nicht sofort aktiviert werden (es sei denn, der Speicher ist knapp, in diesem Fall verschiebt keine der Methoden die Zuweisung).
Stephen Kitt
@ StephenKitt: Du hast wahrscheinlich recht. Ich habe an die spekulative Vorbelegung von XFS gedacht , bei der es erforderlich ist, das Zugriffsmuster zum Schließen / erneuten Öffnen (manchmal für Protokolldateien) zu erkennen.
Peter Cordes
3
In Shells wie bashund mksh, die die Verzweigung für den letzten Befehl in einer Subshell nicht optimieren, können Sie sie etwas effizienter gestalten, indem Sie die Subshell durch eine Befehlsgruppe ersetzen. Für andere Shells sollte dies keine Rolle spielen, und der Ansatz für Subshells ist möglicherweise sogar etwas effizienter, da die Shell stdout nicht speichern und wiederherstellen muss.
Stéphane Chazelas
10

Ich glaube nicht, dass Sie einfach mehrere Dateien in einem einzigen ddAufruf lesen können , aber Sie können die Ausgabedatei in mehreren Schritten anhängen:

dd if=file1 bs=1M count=99 skip=1 of=final_output
dd if=file2 bs=1M count=10 of=final_output oflag=append conv=notrunc

Sie müssen beide conv=notruncund angeben oflag=append. Der erste vermeidet das Abschneiden der Ausgabe, der zweite beginnt mit dem Schreiben am Ende der vorhandenen Datei.

Stephen Kitt
quelle
8

Denken Sie daran , dass ddeine rohe Schnittstelle zu der ist read(), write()und lseek()Systemaufruf. Sie können es nur zuverlässig verwenden, um Datenblöcke aus regulären Dateien, Blockgeräten und einigen Zeichengeräten (z. B. /dev/urandom) zu extrahieren. Dies sind Dateien, für die read(buf, size)eine Rückgabe garantiert ist, sizesolange das Ende der Datei nicht erreicht wird.

Für Pipes, Sockets und die meisten Zeichengeräte (wie ttys) gibt es keine solche Garantie, es sei denn, Sie haben die read()Größe 1 oder verwenden die GNU- ddErweiterung iflag=fullblock.

Also entweder:

{
  gdd < file1 bs=1M iflag=fullblock count=99 skip=1
  gdd < file2 bs=1M iflag=fullblock count=10
} > final_output

Oder:

M=1048576
{
  dd < file1 bs=1 count="$((99*M))" skip="$M"
  dd < file2 bs=1 count="$((10*M))"
} > final_output

Oder mit Shells mit eingebauter Unterstützung für einen Suchoperator wie ksh93:

M=1048576
{
  command /opt/ast/bin/head -c "$((99*M))" < file1 <#((M))
  command /opt/ast/bin/head -c "$((10*M))" < file2
}

Oder zsh(vorausgesetzt, Sie headunterstützen die -cOption hier):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output
Stéphane Chazelas
quelle
Benötigen Sie wirklich die Zitate? Wird das Ergebnis nicht immer eine ganze Zahl sein?
Steven Penny
@StevenPenny, wenn die Erweiterung nicht zitiert wird, wird die Shell gebeten, sie zu splitten + glob, was hier keinen Sinn ergibt. Der aufgeteilte Teil wird mit dem aktuellen Wert von ausgeführt $IFS. Das ist unabhängig vom Inhalt der Variablen / Erweiterung. Siehe auch Auswirkungen auf die Sicherheit, wenn Sie vergessen, eine Variable in bash / POSIX-Shells zu zitieren
Stéphane Chazelas,
@ Stéphane Chazelas - im ersten Beispiel verwenden Sie gddstatt dd. Ist das ein Tippfehler oder ist das beabsichtigt?
Martin Vegter
3

Mit einem Bash- Ismus und einer funktional "nutzlosen Verwendung von cat ", die jedoch der Syntax am nächsten kommt, die das OP verwendet:

cat <(dd if=file1 bs=1M count=99 skip=1) \
    <(dd if=file2 bs=1M count=10) \
   > final_output

(Davon abgesehen scheint Stephen Kitts Antwort die effizienteste Methode zu sein.)

agc
quelle
3
Genau genommen <(...)ist es ein Kshismus, der sowohl kopiert zshals auch bashkopiert wird.
Stéphane Chazelas