Riepilogo: dd
è uno strumento irritabile che è difficile da usare correttamente. Non usarlo, nonostante i numerosi tutorial che lo dicono. dd
ha un'atmosfera da “unix street cred”, ma se capisci veramente cosa stai facendo, saprai che non dovresti toccarlo con un palo da 10 piedi.
dd
effettua una singola chiamata alla chiamata di read
sistema per blocco (definita dal valore di bs
). Non vi è alcuna garanzia che la read
chiamata di sistema restituisca tutti i dati della dimensione del buffer specificata. Questo tende a funzionare per file regolari e dispositivi a blocchi, ma non per pipe e alcuni dispositivi a caratteri. Vedi Quando dd è adatto alla copia dei dati? (o, quando sono read () e write () parziale) per ulteriori informazioni. Se la read
chiamata di sistema restituisce meno di un blocco completo, quindi dd
trasferisce un blocco parziale. Copia ancora il numero specificato di blocchi, quindi la quantità totale di byte trasferiti è inferiore a quella richiesta.
L'avvertimento su una "lettura parziale" dice esattamente questo: una delle letture era parziale, quindi dd
trasferito un blocco incompleto. Nel conteggio dei blocchi, +1
significa che un blocco è stato letto parzialmente; poiché il conteggio delle uscite è +0
, tutti i blocchi sono stati scritti come letti.
Ciò non influisce sulla casualità dei dati: tutti i byte che vengono dd
scritti sono byte da cui vengono letti /dev/urandom
. Ma hai meno byte del previsto.
Linux /dev/urandom
accetta richieste arbitrarie di grandi dimensioni (fonte: extract_entropy_user
in drivers/char/random.c
), quindi dd
è normalmente sicuro quando si legge da esso. Tuttavia, la lettura di grandi quantità di dati richiede tempo. Se il processo riceve un segnale, la read
chiamata di sistema ritorna prima di riempire il buffer di output. Questo è un comportamento normale e le applicazioni dovrebbero chiamare read
in un ciclo; dd
non lo fa, per ragioni storiche ( dd
le origini sono oscure, ma sembra essere nato come uno strumento per accedere ai nastri, che hanno requisiti particolari, e non è mai stato adattato per essere uno strumento generico). Quando si controlla l'avanzamento, questo invia al dd
processo un segnale che interrompe la lettura. Puoi scegliere tra sapere quanti bytedd
copierà in totale (assicurati di non interromperlo - nessun controllo di avanzamento, nessuna sospensione), o sapendo quanti byte dd
ha copiato finora, nel qual caso non puoi sapere quanti più byte copierà.
La versione di dd
in GNU coreutils (come si trova su Linux non incorporato e su Cygwin) ha un flag fullblock
che dice dd
di chiamare read
in un ciclo (e idem per write
) e quindi trasferire sempre blocchi completi. Il messaggio di errore suggerisce che lo usi; dovresti sempre usarlo (in entrambi i flag di input e output), tranne in circostanze molto speciali (soprattutto quando accedi ai nastri) - se lo usi dd
affatto, cioè: di solito ci sono soluzioni migliori (vedi sotto).
dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000
Un altro modo possibile per essere sicuri di cosa dd
farà è passare una dimensione del blocco di 1. Quindi puoi dire quanti byte sono stati copiati dal conteggio dei blocchi, anche se non sono sicuro di cosa accadrà se a read
viene interrotto prima di leggere il primo byte (che non è molto probabile in pratica ma può accadere). Tuttavia, anche se funziona, è molto lento.
Il consiglio generale sull'uso dd
è di non usaredd
. Sebbene dd
sia spesso pubblicizzato come un comando di basso livello per accedere ai dispositivi, in realtà non è una cosa del genere: tutta la magia accade nel file del dispositivo (la /dev/…
) parte, dd
è solo uno strumento normale con un alto potenziale di uso improprio con conseguente perdita di dati . Nella maggior parte dei casi, esiste un modo più semplice e sicuro di fare ciò che vuoi, almeno su Linux.
Ad esempio, per leggere un certo numero di byte all'inizio di un file, basta chiamare head
:
head -c 1000000m </dev/urandom >file
Ho fatto un rapido benchmark sulla mia macchina e non ho osservato alcuna differenza di prestazioni tra dd
con un blocco di grandi dimensioni e head
.
Se è necessario saltare alcuni byte all'inizio, eseguire il pipe tail
in head
:
dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output
Se vuoi vedere i progressi, chiama lsof
per vedere l'offset del file. Funziona solo su un file normale (il file di output sul tuo esempio), non su un dispositivo a caratteri.
lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1
È possibile chiamare pv
per ottenere un rapporto sullo stato di avanzamento (meglio di quello dd
), a spese di un elemento aggiuntivo in cantiere (dal punto di vista delle prestazioni, è appena percettibile).