GNU/Linux >> Linux Esercitazione >  >> Linux

Quando è adatto Dd per copiare i dati? (o, quando sono Read() e Write() parziali)?

Versione breve: In quali circostanze è dd sicuro da usare per copiare i dati, significa che non c'è rischio di danneggiamento a causa di una lettura o scrittura parziale?

Versione lunga — preambolo: dd viene spesso utilizzato per copiare dati, in particolare da o verso un dispositivo (esempio). A volte vengono attribuite proprietà mistiche di poter accedere ai dispositivi a un livello inferiore rispetto ad altri strumenti (quando in realtà è il file del dispositivo a fare la magia), eppure dd if=/dev/sda è la stessa cosa di cat /dev/sda . dd a volte si pensa che sia più veloce, ma cat può batterlo in pratica. Tuttavia, dd ha proprietà uniche che lo rendono davvero utile a volte.

Problema: dd if=foo of=bar non è, infatti, lo stesso di cat <foo >bar . Sulla maggior parte degli unice¹, dd effettua una singola chiamata a read() . (Trovo POSIX sfocato su ciò che costituisce "lettura di un blocco di input" in dd .) Se read() restituisce un risultato parziale (che, secondo POSIX e altri documenti di riferimento, è consentito a meno che la documentazione di implementazione non indichi diversamente), viene copiato un blocco parziale. Esattamente lo stesso problema esiste per write() .

Osservazioni :In pratica, ho trovato che dd può far fronte a dispositivi a blocchi e file regolari, ma potrebbe essere solo che non l'ho esercitato molto. Quando si tratta di pipe, non è difficile inserire dd in colpa; ad esempio prova questo codice:

yes | dd of=out bs=1024k count=10

e controlla la dimensione del out file (è probabile che sia ben inferiore a 10 MB).

Domanda :In quali circostanze è dd sicuro da usare per copiare i dati? In altre parole, quali condizioni sulle dimensioni dei blocchi, sull'implementazione, sui tipi di file, ecc. possono garantire che dd copierà tutti i dati?

(GNU dd ha un fullblock flag per dirgli di chiamare read() o write() in un ciclo in modo da trasferire un blocco completo. Quindi dd iflag=fullblock è sempre al sicuro. La mia domanda riguarda il caso in cui questi flag (che non esistono su altre implementazioni) non vengono utilizzati.)

¹
Ho controllato su OpenBSD, GNU coreutils e BusyBox.

Risposta accettata:

Dalle specifiche:

  • Se il bs= expr è specificato l'operando e nessuna conversione diversa da sync , noerror , o notrunc sono richiesti, i dati restituiti da ciascun blocco di ingresso devono essere scritti come un blocco di uscita separato; se il read() restituisce meno di un blocco completo e sync conversione non è specificata, il blocco di output risultante deve avere le stesse dimensioni del blocco di input.

Quindi questo è probabilmente ciò che causa la tua confusione. Sì, perché dd è progettato per il blocco, per impostazione predefinita parziale read() s verrà mappato 1:1 su write() parziale s, oppure sync d out on tail padding NUL o caratteri spaziali su bs= dimensione quando conv=sync è specificato.

Ciò significa che dd è sicuro da usare per copiare i dati (senza rischio di danneggiamento dovuto a una lettura o scrittura parziale) in ogni caso tranne uno in cui è arbitrariamente limitato da un count= argomento, perché altrimenti dd sarà felicemente write() il suo output in blocchi di dimensioni identiche a quelli in cui il suo input era read() finché non read() s completamente attraverso di esso. E anche questo avvertimento è solo vero quando bs= è specificato o obs= è non specificato, come afferma la frase successiva nelle specifiche:

  • Se il bs= expr l'operando non è specificato o una conversione diversa da sync , noerror , o notrunc viene richiesto, l'input deve essere elaborato e raccolto in blocchi di output a grandezza naturale fino al raggiungimento della fine dell'input.
Correlati:Debian – perdita ricorrente della connettività wireless?

Senza ibs= e/o obs= argomenti questo non può importare, perché ibs e obs sono entrambi della stessa dimensione per impostazione predefinita. Tuttavia, puoi essere esplicito sul buffer di input specificando diverse dimensioni per entrambi e non specificando bs= (perché ha la precedenza) .

Ad esempio, se lo fai:

IN| dd ibs=1| OUT

…quindi un POSIX dd write() in blocchi di 512 byte raccogliendo ogni singolo read() byte in un unico blocco di uscita.

Altrimenti, se lo fai...

IN| dd obs=1kx1k| OUT

…a POSIX dd read() al massimo 512 byte alla volta, ma write() ogni blocco di output della dimensione di un megabyte (kernel che consente ed eccettuato forse l'ultimo, perché è EOF) per intero raccogliendo l'input in blocchi di output a grandezza naturale .

Anche dalle specifiche, però:

  • count=n
    • Copia solo n blocchi di input.

count= mappa a i?bs= blocchi, e così via per gestire un limite arbitrario su count= in modo portatile avrai bisogno di due dd S. Il modo più pratico per farlo con due dd s è convogliando l'output di uno nell'input di un altro, il che sicuramente ci pone nel regno della lettura/scrittura di un file speciale indipendentemente dal tipo di input originale.

Una pipe IPC significa che quando si specifica [io]bs= args che, per farlo in sicurezza, devi mantenere tali valori all'interno del PIPE_BUF definito dal sistema limite. POSIX afferma che il kernel di sistema deve garantire solo read() atomico se write() s entro i limiti di PIPE_BUF come definito in limits.h . POSIX garantisce che PIPE_BUF essere almeno

  • {_POSIX_PIPE_BUF}
    • Numero massimo di byte che è garantito essere atomico durante la scrittura su una pipe.
    • Valore:512

(che è anche il dd predefinito i/o blocksize) , ma il valore effettivo di solito è almeno 4k. Su un sistema Linux aggiornato è, per impostazione predefinita, 64k.

Quindi, quando imposti il ​​tuo dd processi dovresti farlo su un blocco fattore in base a tre valori:

  1. bs =( obs =PIPE_BUF o inferiore)
  2. n =numero totale desiderato di byte letti
  3. conteggio =n / b

Come:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

Devi sincronizzare i/o con dd per gestire input non ricercabili. In altre parole, rendi espliciti i pipe-buffer e smettono di essere un problema. Ecco cosa dd è per. L'incognita qui è yes è la dimensione del buffer, ma se lo blocchi a un conosciuto quantità con un altro dd quindi una piccola moltiplicazione informata può fare dd sicura da usare per copiare i dati (senza rischio di danneggiamento a causa di una lettura o scrittura parziale) anche quando si limita arbitrariamente l'input con count= con qualsiasi tipo di input arbitrario su qualsiasi sistema POSIX e senza perdere un singolo byte.

Ecco uno snippet delle specifiche POSIX:

  • ibs= expr
    • Specifica la dimensione del blocco di input, in byte, tramite expr (il valore predefinito è 512) .
  • obs= expr
    • Specifica la dimensione del blocco di output, in byte, tramite expr (il valore predefinito è 512) .
  • bs= expr
    • Imposta le dimensioni dei blocchi di input e output su expr byte, sostituendo ibs= e obs= . Se nessuna conversione diversa da sync , noerror e notrunc è specificato, ogni blocco di ingresso deve essere copiato nell'uscita come blocco singolo senza aggregare blocchi brevi.
Correlati:come fare in modo che il terminale visualizzi [protetto dalla posta elettronica] in grassetto?

Troverai anche alcuni di questi spiegati meglio qui.


Linux
  1. Leggi e scrivi dati da qualsiasi luogo con reindirizzamento nel terminale Linux

  2. Usa il comando Netcat per leggere e scrivere dati attraverso la rete su Ubuntu 20.04

  3. Comando bsdtar – Legge e scrive file di archivio su nastro

  4. Quando dovrei usare TCP_NODELAY e quando TCP_CORK?

  5. Come aprire, leggere e scrivere dalla porta seriale in C?

Come utilizzare il comando Netcat per leggere e scrivere dati attraverso la rete

Trucchi e scherzetti per amministratori di sistema e operatori

Come installare e utilizzare Okteta per file di dati RAW in Linux

Annunci di testo pay per click per avvocati e avvocati

Che cos'è un database distribuito e a cosa servono i sistemi di dati distribuiti?

I 15 migliori software econometrico e statistico per sistemi Linux