Podsumowanie: dd
jest zepsutym narzędziem, które jest trudne w użyciu poprawnie. Nie używaj go, pomimo licznych samouczków, które ci to mówią. dd
ma w sobie klimat „unix street cred” - ale jeśli naprawdę rozumiesz, co robisz, będziesz wiedział, że nie powinieneś dotykać go 10-metrowym drągiem.
dd
wykonuje pojedyncze wywołanie wywołania read
systemowego na blok (zdefiniowane przez wartość bs
). Nie ma gwarancji, że read
wywołanie systemowe zwróci tyle danych, ile podany rozmiar bufora. Zwykle działa to na zwykłe pliki i urządzenia blokujące, ale nie na potoki i niektóre urządzenia znakowe. Zobacz Kiedy dd nadaje się do kopiowania danych? (lub, gdy są czytane () i write () częściowe), aby uzyskać więcej informacji. Jeśli read
wywołanie systemowe zwraca mniej niż jeden pełny blok, wówczas dd
przenosi blok częściowy. Nadal kopiuje określoną liczbę bloków, więc całkowita liczba przesłanych bajtów jest mniejsza niż wymagana.
Ostrzeżenie o „częściowym odczycie” mówi dokładnie to: jeden z odczytów był częściowy, więc dd
przekazano niepełny blok. W liczeniu bloków +1
oznacza, że jeden blok został częściowo odczytany; ponieważ liczba wyjść jest taka +0
, wszystkie bloki zostały zapisane jako przeczytane.
Nie wpływa to na losowość danych: wszystkie bajty, które dd
wypisują, są bajtami, które odczytały /dev/urandom
. Ale masz mniej bajtów niż oczekiwano.
Linux /dev/urandom
obsługuje dowolne duże żądania (source: extract_entropy_user
in drivers/char/random.c
), więc dd
zwykle jest bezpieczny podczas czytania z niego. Jednak czytanie dużych ilości danych wymaga czasu. Jeśli proces odbierze sygnał, read
wywołanie systemowe powraca przed zapełnieniem bufora wyjściowego. Jest to normalne zachowanie, a aplikacje powinny wywoływać się read
w pętli; dd
nie robi tego z przyczyn historycznych ( dd
pochodzenie jest niejasne, ale wydaje się, że zaczęło się jako narzędzie dostępu do taśm, które mają specyficzne wymagania i nigdy nie zostało przystosowane do tego, by być narzędziem ogólnego zastosowania). Gdy sprawdzasz postęp, wysyła do dd
procesu sygnał, który przerywa odczyt. Masz wybór między wiedzą, ile bajtówdd
skopiuje w całości (pamiętaj, aby go nie przerwać - bez sprawdzania postępu, bez zawieszenia) lub wiedząc, ile bajtów dd
skopiowano do tej pory, w takim przypadku nie możesz wiedzieć, ile jeszcze bajtów skopiuje.
Wersja dd
w GNU coreutils (znaleziona w niewbudowanym systemie Linux i na Cygwin) ma flagę, fullblock
która mówi, dd
aby wywoływać read
w pętli (i to samo dla write
), a zatem zawsze przenosić pełne bloki. Komunikat o błędzie sugeruje jego użycie; powinieneś zawsze go używać (zarówno w flagach wejściowych, jak i wyjściowych), z wyjątkiem bardzo szczególnych okoliczności (głównie podczas uzyskiwania dostępu do taśm) - jeśli dd
w ogóle używasz , to znaczy: zwykle są lepsze rozwiązania (patrz poniżej).
dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000
Innym możliwym sposobem na upewnienie się, co się dd
stanie, jest przekazanie bloku o rozmiarze 1. Następnie możesz powiedzieć, ile bajtów zostało skopiowanych z liczby bloków, chociaż nie jestem pewien, co się stanie, jeśli a read
zostanie przerwane przed przeczytaniem pierwszego bajt (co w praktyce jest mało prawdopodobne, ale może się zdarzyć). Jednak nawet jeśli to działa, jest to bardzo powolne.
Według opinii na temat używania dd
jest nie używaćdd
. Chociaż dd
jest często reklamowany jako polecenie niskiego poziomu dostępu do urządzeń, w rzeczywistości nie ma takiej rzeczy: cała magia dzieje się w części pliku urządzenia /dev/…
, dd
jest zwykłym narzędziem o wysokim potencjale niewłaściwego użycia powodującego utratę danych . W większości przypadków istnieje prostszy i bezpieczniejszy sposób robienia tego, co chcesz, przynajmniej w systemie Linux.
Na przykład, aby odczytać określoną liczbę bajtów na początku pliku, wystarczy wywołać head
:
head -c 1000000m </dev/urandom >file
Zrobiłem szybki test porównawczy na mojej maszynie i nie zauważyłem żadnej różnicy w wydajności między dd
dużym blokiem a head
.
Jeśli musisz pominąć kilka bajtów na początku, potokuj tail
do head
:
dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output
Jeśli chcesz zobaczyć postęp, zadzwoń, lsof
aby zobaczyć przesunięcie pliku. Działa to tylko na zwykłym pliku (plik wyjściowy na twoim przykładzie), a nie na urządzeniu znakowym.
lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1
Możesz zadzwonić, pv
aby uzyskać raport postępu (lepszy niż dd
), kosztem dodatkowego elementu w potoku (pod względem wydajności jest to ledwo zauważalne).