dd vs cat - czy dd jest nadal aktualne?

122

Niedawno zdałem sobie sprawę, że możemy zużyć cattyle dd, ile jest i tak naprawdę szybciejdd

Wiem, że ddbyło to przydatne w przypadku taśm, w których rozmiar bloku rzeczywiście miał znaczenie dla poprawności, a nie tylko wydajności. Czy w dzisiejszych czasach są sytuacje, w których ddmożna zrobić coś, czego catnie można? (Uważam, że różnica wydajności mniejsza niż 20% jest nieistotna.)

Przydałyby się konkretne przykłady!

kizzx2
źródło
1
Zobacz to SO dla jednego konkretnego przykładu.
camh

Odpowiedzi:

156

Z wyglądu ddjest narzędziem systemu operacyjnego IBM, które zachowało swój obcy wygląd (przekazywanie parametrów), który wykonuje niektóre bardzo rzadko używane funkcje (takie jak konwersje EBCDIC do ASCII lub odwracanie endianizmu… obecnie nie jest to powszechna potrzeba).

I używany do myślenia , że ddbył szybszy do kopiowania dużych bloków danych na tym samym dysku (ze względu na bardziej efektywne wykorzystanie buforowania), ale to nie jest prawda , przynajmniej w dzisiejszych systemach Linux.

Myślę, że niektóre ddopcje są przydatne podczas pracy z taśmami, gdzie czytanie odbywa się naprawdę w blokach (sterowniki taśm nie ukrywają bloków na nośniku pamięci tak, jak robią to sterowniki dysków). Ale nie znam szczegółów.

Jedną rzeczą dd, której nie można (łatwo) zrobić za pomocą innego narzędzia POSIX, jest pobranie pierwszych N bajtów strumienia. Wiele systemów może to zrobić head -c 42, ale head -cchociaż jest to wspólne, nie ma go w POSIX (i nie jest dziś dostępne np. W OpenBSD). ( tail -cjest POSIX). Ponadto, nawet jeśli head -cistnieje, może odczytać zbyt wiele bajtów ze źródła (ponieważ korzysta z wewnętrznego buforowania stdio), co jest problemem, jeśli czytasz ze specjalnego pliku, w którym samo czytanie ma wpływ. (Obecne jądra GNU odczytują dokładną liczbę head -c, ale FreeBSD i NetBSD używają stdio.)

Mówiąc bardziej ogólnie, ddzapewnia interfejs do bazowego interfejsu API plików, który jest unikalny wśród narzędzi uniksowych: ddmoże tylko nadpisywać lub obcinać plik w dowolnym momencie lub wyszukiwać w pliku. (Jest to ddwyjątkowa umiejętność, i jest to duża; dość dziwnie ddnajlepiej znana jest z rzeczy, które mogą zrobić inne narzędzia.)

  • Większość narzędzi uniksowych zastępuje swój plik wyjściowy, tj. Usuwa jego zawartość i uruchamia od nowa. Tak dzieje się również wtedy, gdy używasz >przekierowania w powłoce.
  • Możesz dołączyć do zawartości pliku z >>przekierowaniem w powłoce lub za pomocą tee -a.
  • Jeśli chcesz skrócić plik, usuwając wszystkie dane po pewnym czasie , jest to obsługiwane przez jądro i interfejs API C za pośrednictwem truncatefunkcji, ale nie jest ujawniane przez żadne narzędzie wiersza poleceń, z wyjątkiemdd :

    dd if=/dev/null of=/file/to/truncate seek=1 bs=123456  # truncate file to 123456 bytes
    
  • Jeśli chcesz zastąpić dane w środku pliku, znowu jest to możliwe w underyling API, otwierając plik do zapisu bez obcinania (i lseekw razie potrzeby wywołując przejście do żądanej pozycji), ale ddmożna tylko otworzyć plik bez obcinanie lub dołączanie lub wyszukiwanie w powłoce ( bardziej złożony przykład ).

    # zero out the second kB block in the file (i.e. bytes 1024 to 2047)
    dd if=/dev/zero of=/path/to/file bs=1024 seek=1 count=1 conv=notrunc
    

Więc… Jako narzędzie systemowe ddjest prawie bezużyteczne. Jako narzędzie do przetwarzania tekstu (lub pliku binarnego) jest bardzo cenne!

Gilles
źródło
Zaakceptowano, ponieważ myślę, że wyjaśnia sedno innych odpowiedzi ( trunci seekjest użyteczny dd).
kizzx2
2
Jeszcze jedno specjalne zastosowanie: ddmoże odczytać dane binarne z niewidzialnych deskryptorów plików bez potencjalnego zniszczenia nieprzeczytanych danych z powodu buforowania standardowego. Zobacz tutaj przykład: etalabs.net/sh_tricks.html
R ..
2
@R ..: Tak. W GNU coreutils 6.10 head -c Nwywołuje readi nigdy nie wykracza poza N. W NetBSD 5.1, head -cpołączenia getc. We FreeBSD 7.4 head -cwywołania fread.
Gilles
1
Coreutils ddnaraża również O_DIRECT (itp.) Na wykonywanie skryptów powłoki, co moim zdaniem jest również unikalne.
derobert
1
Coreutils truncatepozwala obcinać lub rozszerzać pliki, eliminując w ten sposób inne użycie dd.
dcoles,
22

ddKomenda zawiera wiele opcji, że kot nie jest w stanie pomieścić. Być może w twoich przypadkach użycia kot jest praktycznym zamiennikiem, ale nie zastępuje dd.

Jednym z przykładów byłoby użycie dddo skopiowania części czegoś, ale nie całej. Być może chcesz wyrwać niektóre bity ze środka obrazu ISO lub tablicy partycji z dysku twardego na podstawie znanej lokalizacji na urządzeniu. Za pomocą ddmożesz określić opcje rozpoczęcia, zatrzymania i ilości, które pozwalają na te działania.

Te opcje ddsprawiają, że jest on niezbędny do precyzyjnej manipulacji danymi, podczas gdy cat* może działać tylko na obiektach, urządzeniach lub strumieniach całego pliku.

* Jak zauważył Gilles w komentarzach, można łączyć się catz innymi narzędziami do izolowania części czegoś, ale catnadal działa na całym obiekcie.

Caleb
źródło
5
ddw rzeczywistości nie ma nic wspólnego z urządzeniami niskiego poziomu, wymaga wejścia, /devpodobnie jak inne. Możesz skopiować całą partycję za pomocą catlub jej część za pomocą tail +c $(($start+1)) | head -c $count.
Gilles
16
Oczywiście. ;-) A kiedy podaję obraz dysku o pojemności 1,6 TB, cat | head | tailaby pobrać kilka ostatnich MB, wirowanie dysku zasysa księżyc bliżej ziemi.
Caleb
2
@Gilles Przepraszam, chciałem przyznać, że moje użycie terminu „niski poziom” nie było zbyt dobrą dykcją, chociaż miałem na myśli dane na urządzeniach, a nie urządzeniach. Być może lepsze byłoby „dokładne dostrojenie manipulacji danymi” niż „manipulowanie danymi niskiego poziomu”.
Caleb
21

Nikt jeszcze nie wspomniał, że możesz użyć dd do tworzenia rzadkich plików , choć truncatemożna go również użyć do tego samego celu.

dd if=/dev/zero of=sparse-file bs=1 count=1 seek=10GB

Jest to prawie natychmiastowe i tworzy dowolny duży plik, który można wykorzystać jako plik pętli zwrotnej na przykład:

loop=`losetup --show -f sparse-file`
mkfs.ext4 $loop
mkdir myloop
mount $loop myloop

Zaletą jest to, że początkowo używa tylko jednego bloku miejsca na dysku, a następnie rośnie tylko w razie potrzeby (formatowanie ext4 pliku 10 GB zużywa 291 MB w moim systemie). Służy dudo sprawdzania, ile miejsca na dysku jest faktycznie używane - lszgłasza tylko maksymalny rozmiar pliku, do którego może wzrosnąć.

Lauritz V. Thaulow
źródło
4
ls -lspokazuje rzadki rozmiar.
jmtd,
2
Twoje polecenie zapisuje w pliku bezużyteczny bajt. dd of=sparse-file bs=1 count=0 seek=10Gbyłoby równoważne z truncate -s 10GB sparse-file. Dość mylące truncatei ddmieć dokładnie przeciwną interpretację GBvs. G...
frostschutz
5
@frostschutz: man ddmówi: MB =1000*1000, M =1024*1024i tak dalej. I man truncatemówi: MB 1000*1000, M 1024*1024więc nie ma różnicy. Używam obu ddi truncatez GNU coreutils. Ty też powinieneś to zrobić! :-)
erik
@erik: Dzięki za korektę. Jeśli to się ostatnio nie zmieniło, musiałem jakoś pomylić to z czymś innym.
frostschutz
10

Często zastępuj określone segmenty dysku twardego zwykłym przykładem. Na przykład możesz chcieć usunąć swój MBR za pomocą tego polecenia:

dd if=/dev/zero of=/dev/sda bs=446 count=1

Możesz również tworzyć przy nim puste pliki (powiedzmy na obrazy dysków pętli):

dd if=/dev/zero of=10mb.file bs=1024k count=10
XQYZ
źródło
Nawiasem mówiąc, to drugie polecenie jest najszybszym znanym mi sposobem na użycie do 10 MB
Kevin M
3
@Kevin: Szybciej niż head -c? Udostępnij test porównawczy !
Gilles
9

ddjest bardzo przydatny do tworzenia kopii zapasowych sektora rozruchowego dysku twardego lub innego urządzenia pamięci masowej ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1), a następnie przepisywania go ( dd if=boot_sector.bin of=/dev/sda). Jest to również przydatne do tworzenia kopii zapasowych nagłówków zaszyfrowanych woluminów.

catbyć może uda się to zrobić, ale nie ufałbym temu w części przepisywania. Trudno jest catodczytać / zapisać tylko określoną liczbę bajtów.

LawrenceC
źródło
5

Ostatnio miałem okazję sklonować kilka partycji o rozmiarze 100 GB z GB po raz pierwszy w mojej historii linuksowania (por. cp -arLub rsyncktóre służyły mi wiele razy). Oczywiście zwróciłem się do ddtego, ponieważ wszyscy wiedzą, że tego używasz ... i byłem przerażony występem. Wkrótce doprowadziło mnie trochę googlingu ddrescue, z którego korzystałem już kilka razy i działa znakomicie (znacznie szybciej niż dd).

czas
źródło
1
ddrescuejest świetny, szczególnie do pobierania danych z uszkodzonych dysków.
ryenus
5

Oto kilka sztuczek dd, które wymyśliłem przez lata ..

Wytnij i wklej w nieprzyjaznym bicie w trybie tty lub nieinteraktywnym

Jeśli jesteś w sytuacji, gdy EOF / ^ D / ^ F nie zostanie wykryty, możesz użyć dd do przesłania plików tekstowych do hosta. Ponieważ przestanie czytać automatycznie po określonej ilości bajtów.

Użyłem tego jeszcze w zeszłym roku podczas ćwiczenia bezpieczeństwa, w którym mogliśmy uzyskać powłoki non-tty na zdalnym hoście i potrzebowaliśmy przenieść pliki.

W rzeczywistości zrobiłem nawet kilka plików binarnych, kodując je base64 i używając powolnego, ale niezawodnego skryptu dekodowania base64 w czystym stylu.

dd of=textfile.txt bs=1 count=<size_of_data_in_paste_buffer>

Super fajna sztuczka polega na tym, że gdy dd jest uruchomiony, jeśli wyślesz mu sygnał USR1, wyemituje swój bieżący status (odczytane bajty, bajty na sekundę ..)

Uniwersalny filtr stanu przepustowości

Napisałem to, aby działało jako czysty filtr postępu dla każdego programu, który emituje dane przez standardowe wyjście. (Uwaga: prawie wszystko wysyła dane przez stdout - w przypadku programów, które tego nie robią, możesz oszukiwać, jeśli nie przeszkadzają ci przy użyciu / dev / stdout jako nazwy pliku. Ale pomysł jest w zasadzie za każdym razem, gdy dostajesz X ilość bajtów, wydrukuj znaki skrótu (jak oldschoolowy FTP, gdy miałeś włączony tryb skrótu)

(Uwaga) Plik postępu jest kiepski, był to głównie dowód koncepcji. Gdybym to zrobił, użyłbym zmiennej.

 dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -E '[[:digit:]]* bytes' \
                | awk '{ print $1 }' >> ${PROGRESS} &

 while [[ $(pidof dd) -gt 1 ]]; do

        # PROTIP: You can sleep partial seconds
        sleep .5

        # Force dd to update us on it's progress (which gets
        # redirected to $PROGRESS file.    
        pkill -USR1 dd
        local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
        local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))

        if [ $XFER_BLKS -gt 0 ]; then
                printf "#%0.s" $(seq 0 $XFER_BLKS)
                BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
        fi
done

wycinanie i krojenie plików za pomocą anonimowych uchwytów plików powłoki

Oto niezwykle pseudo-kodowy przykład tego, w jaki sposób można podpisać plik tar, który można wyodrębnić bez błędów, wprowadzając dane tar za pomocą anonimowego uchwytu pliku - bez użycia plików tmp do przechowywania częściowych danych pliku.

generate_hash() {
    echo "yay!"
}

# Create a tar file, generate a hash, append it to the end
tar -cf log.tar /var/log/* 2>/dev/null
TARFILE_SIZE=$(stat -f "%z" log.tar)
SIGNATURE=$(generate_hash log.tar)
echo $SIGNATURE >>log.tar

# Then, later, extract without getting an error..

tar xvf <(dd if=$OLDPWD/log.tar bs=1 count=${TARFILE_SIZE})

Tl; dr to: uważam, że dd jest niezwykle przydatny. A to tylko trzy przykłady, które mogę wymyślić z góry.

synthesizerpatel
źródło
4

Możesz przekierować część treści wyjściowej. Jest to szczególnie przydatne, jeśli chcesz pisać sudo:

echo some_content | sudo dd status=none of=output.txt

Poza tym sudojest to równoważne z:

echo some_content > output.txt

lub do tego:

echo some_content | sudo tee output.txt > /dev/null
Alexey
źródło