dd: più file di input


14

Devo concatenare blocchi da due file:

se avessi bisogno di concatenare interi file, potrei semplicemente farlo

cat file1 file2 > output

Ma devo saltare i primi 1 MB dal primo file e voglio solo 10 MB dal secondo file. Sembra un lavoro per 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

C'è la possibilità di farlo in un solo passaggio? cioè, senza la necessità di salvare i risultati intermedi? Posso usare più file di input in dd?

Risposte:


21

dd può scrivere anche su stdout.

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

Questo è probabilmente il modo migliore. Il file di output non viene chiuso / riaperto (come è con oflag=append conv=notrunc), quindi i file system che eseguono l'allocazione ritardata (come XFS) hanno meno probabilità di decidere che il file è stato scritto quando c'è ancora molto da fare.
Peter Cordes,

@PeterCordes questo è un buon punto, ma finché ddnon viene richiesto sync, l'allocazione ritardata non dovrebbe comunque iniziare immediatamente (a meno che la memoria non sia stretta in tal caso nessuno dei due metodi rimanderà l'allocazione).
Stephen Kitt,

@StephenKitt: Probabilmente hai ragione. Stavo pensando alla preallocazione speculativa di XFS , in cui è necessario rilevare appositamente il modello di accesso di chiusura / riapertura (a volte visto per i file di registro).
Peter Cordes,

3
In shell come bashe mkshche non ottimizzano il fork per l'ultimo comando in una subshell, è possibile renderlo leggermente più efficiente sostituendo la subshell con un gruppo di comandi. Per altre shell, non dovrebbe importare, e l'approccio subshell potrebbe anche essere leggermente più efficiente in quanto la shell non ha bisogno di salvare e ripristinare stdout.
Stéphane Chazelas,

10

Non penso che tu possa leggere facilmente più file in una singola ddchiamata, ma puoi aggiungere per creare il file di output in diversi passaggi:

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

Devi specificare sia conv=notrunce oflag=append. Il primo evita di troncare l'output, il secondo inizia a scrivere dalla fine del file esistente.


8

Tenete a mente che ddè un'interfaccia prima al read(), write()e lseek()chiamata di sistema. Puoi usarlo in modo affidabile solo per estrarre blocchi di dati da file regolari, bloccare dispositivi e alcuni dispositivi a caratteri (come /dev/urandom), ovvero file per i quali read(buf, size)è garantito il ritorno sizefino a quando non viene raggiunta la fine del file.

Per tubi, prese e la maggior parte dei dispositivi a carattere (come ttys), non hai tale garanzia a meno che non fai read()s di dimensione 1 o usi l' ddestensione GNU iflag=fullblock.

Quindi neanche:

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

O:

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

O con shell con supporto integrato per un operatore di ricerca come ksh93:

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

Oppure zsh(supponendo che headl' -copzione supporti qui):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output

Hai davvero bisogno delle virgolette? Il risultato non sarà sempre un numero intero?
Steven Penny,

@StevenPenny, lasciando l'espansione non quotata, chiede alla shell di dividerla + glob che non avrebbe alcun senso qui. La parte divisa viene eseguita sul valore corrente di $IFS. Questo indipendentemente dal contenuto della variabile / espansione. Vedi anche Implicazioni sulla sicurezza dell'oblio di citare una variabile nelle shell bash / POSIX
Stéphane Chazelas,

@ Stéphane Chazelas - nel primo esempio, stai usando gddinvece di dd. È un errore di battitura o è intenzionale?
Martin Vegter,

3

Con un bash ismo e un "uso inutile del gatto " funzionalmente, ma più vicino alla sintassi che utilizza l'OP:

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

(Detto questo, la risposta di Stephen Kitt sembra essere il metodo più efficiente possibile.)


3
A rigor di termini, <(...)è un kshism che sia zshe bashcopiato.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.