Nedávno jsem si uvědomil, že můžeme použít cat
stejně jako dd
, a je to ve skutečnosti rychlejší než dd
Vím, že dd
byl užitečný při práci s páskami, u kterých ve skutečnosti na velikosti bloku záleželo na správnosti, nejen na výkonu. V těchto dnech však existují situace, kdy dd
může něco udělat cat
nemůže? (Zde bych považoval rozdíl výkonu méně než 20% za irelevantní.)
Konkrétní příklady by byly pěkné!
Ve vzhledu dd
je nástroj z operačního systému IBM, který si zachoval svůj zahraniční vzhled (předávání parametrů), který vykonává některé velmi zřídka používané funkce (například EBCDIC na ASCII konverze nebo obrácení endianness… dnes není běžná potřeba).
I zvyklý si myslet , že dd
byl rychlejší pro kopírování velkých bloků dat na stejný disk (kvůli efektivnějšímu využití ukládání do vyrovnávací paměti), ale toto není pravda , alespoň na dnešních Linuxových systémech.
Myslím, že některé z možností dd
jsou užitečné při práci s páskami, kde je čtení skutečně prováděno v blocích (páskové ovladače neskrývají bloky na paměťovém médiu tak, jak to činí diskové ovladače). Ale neznám podrobnosti.
Jedna věc dd
, kterou nelze (snadno) provést jiným nástrojem POSIX, je odebrání prvních N bajtů proudu. Mnoho systémů to dokáže s head -c 42
, Ale head -c
, I když je běžné, není v POSIXu (a není dnes k dispozici například na OpenBSD). (tail -c
Je POSIX.) Také, i když head -c
Existuje, může ze zdroje číst příliš mnoho bytů (protože interně používá stdio buffering), což je problém, pokud čtete ze zvláštního souboru, kde má efekt jen čtení. (Aktuální GNU coreutils čtou přesný počet s head -c
, Ale FreeBSD a NetBSD používají stdio.)
Obecněji platí, že dd
poskytuje rozhraní pro základní souborové rozhraní API, které je jedinečné mezi unixovými nástroji: pouze dd
může přepsat nebo zkrátit soubor v kterémkoli bodě nebo hledejte v souboru. (Toto je jedinečná schopnost dd
a je to velká; kupodivu dd
je nejlépe známá pro věci, které mohou dělat jiné nástroje.)
>
Ve skořápce.>>
Ve skořápce nebo pomocí tee -a
.Pokud chcete soubor zkrátit odstraněním všech dat po určitém bodě, je to podporováno základním jádrem a C API skrz truncate
funkce, ale nebyla vystavena žádným nástrojem příkazového řádku kromě dd
:
dd if=/dev/null of=/file/to/truncate seek=1 bs=123456 # truncate file to 123456 bytes
Pokud chcete přepsat data uprostřed souboru, je to opět možné v API pro underyling otevření soubor pro zápis bez zkrácení (a volání lseek
) pro přesun na požadované místo, je-li to nutné), ale pouze dd
může otevřít soubor bez zkrácení nebo připojení, nebo hledat z prostředí ( složitější příklad) ).
# 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
Takže ... Jako systémový nástroj je dd
k ničemu. Jako nástroj pro zpracování textu (nebo binárního souboru) je to docela cenné!
Příkaz dd
obsahuje LOTS možností, které kočka nemůže vyhovět. Možná ve vašich případech použití je kočka funkční náhradou, ale není to náhrada dd.
Jedním příkladem by bylo použití dd
ke zkopírování části něčeho, ale ne celé věci. Možná budete chtít vytrhnout některé bity ze středu obrazu iso nebo tabulky oddílů z pevného disku na základě známého umístění v zařízení. Pomocí dd
můžete určit možnosti spuštění, zastavení a množství, které tyto akce povolí.
Díky těmto možnostem dd
je nepostradatelná pro manipulaci s jemně zrnitými daty, zatímco cat
* může pracovat pouze na celých souborových objektech, zařízeních nebo proudech.
* Jak poznamenal Gilles v komentářích, je možné kombinovat cat
s jinými nástroji k izolování částí něčeho, ale cat
stále funguje na celém objektu.
Zatím nikdo nezmínil, že můžete použít dd k vytvoření řídké soubory , ale truncate
lze také použít pro stejný účel.
dd if=/dev/zero of=sparse-file bs=1 count=1 seek=10GB
Toto je téměř okamžité a vytváří libovolný velký soubor, který lze použít například jako soubor zpětné smyčky:
loop=`losetup --show -f sparse-file`
mkfs.ext4 $loop
mkdir myloop
mount $loop myloop
Dobrá věc je, že zpočátku používá pouze jeden blok místa na disku a poté roste pouze podle potřeby (formátování ext4 10 GB souboru v mém systému spotřebuje 291 MB). Pomocí du
zjistíte, kolik místa na disku se skutečně používá - ls
hlásí pouze maximální velikost, do které může soubor narůstat.
Přepsat konkrétní segmenty pevného disku něčím je běžným příkladem. Například můžete chtít odstranit svůj MBR pomocí tohoto příkazu:
dd if=/dev/zero of=/dev/sda bs=446 count=1
Můžete si také vytvořit prázdné soubory (řekněme pro obrazy diskových smyček):
dd if=/dev/zero of=10mb.file bs=1024k count=10
dd
je velmi užitečné pro zálohování spouštěcího sektoru pevného disku nebo jiného úložného zařízení (dd if=/dev/sda of=boot_sector.bin bs=512 count=1
) a později jej přepisovat (dd if=boot_sector.bin of=/dev/sda
). Podobně je to užitečné pro zálohování záhlaví šifrovaných svazků.
cat
by to bylo možné zkrotit, ale v přepisovací části bych tomu nevěřil. Je obtížné přimět cat
, aby četl/zapisoval pouze určitý počet bytů.
Nedávno jsem měl poprvé v mém historii linuxingu klonování některých oddílů s více než 100 s-GB (c.f cp -ar
nebo rsync
, které mi sloužily mnohokrát). Samozřejmě jsem se obrátil na dd
'protože každý ví, že to, co používáte ... a byl výkonem zděšen. Trocha googlingů mě brzy dovedla k ddrescue
, který jsem už několikrát použil a funguje skvěle dobře (mnohem rychleji než dd).
Zde je několik triků, s nimiž jsem během let přišel ..
Pokud jste v situaci, kdy EOF/^ D/^ F není detekován, můžete pomocí dd přenést textové soubory na hostitele. Protože se automaticky zastaví čtení po určitém počtu bajtů.
Použil jsem to teprve nedávno v minulém roce v rámci bezpečnostního cvičení, kde jsme byli schopni získat netypické náboje na vzdáleném hostiteli a potřebovali jsme je přenést.
Ve skutečnosti jsem dokonce udělal pár binárních souborů pomocí kódování base64 a pomocí pomalého, ale spolehlivého čistě bashového dekódovacího skriptu base64.
dd of=textfile.txt bs=1 count=<size_of_data_in_paste_buffer>
Super cool trik je v tom, že zatímco běží dd, pokud mu pošlete signál USR1, bude vysílat jeho aktuální stav (čtení bytů, bajtů za sekundu ..)
Napsal jsem to, aby fungoval jako čistě bash filter pro jakýkoli program, který vydává data prostřednictvím stdout. (Poznámka: Téměř cokoli bude emitovat data prostřednictvím stdout - pro programy, které tak neučiní, můžete podvádět, pokud se vám nelíbí pomocí/dev/stdout jako názvu souboru. Tento nápad je v podstatě pokaždé, když dostanete X množství bajtů, tisk hashovacích značek (jako starý školní FTP, když jste měli hashovací režim)
(Poznámka) Věc v souboru pokroku je chromá, většinou to byl důkaz o konceptu. Kdybych to redidoval, použil bych jen proměnnou.
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
Zde je extrémně pseudokódový příklad toho, jak můžete mít podepsaný soubor dehtu, který můžete extrahovat bez chyb, poskytnutím vstupu dehtu prostřednictvím anonymního filehandle - bez použití jakýchkoli souborů tmp k ukládání dílčích dat souboru.
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})
The tl; dr je: Považuji dd za neuvěřitelně užitečné. A to jsou jen tři příklady, na které si pomyslím mimo temeno hlavy.
Můžete přesměrovat nějaký výstupní obsah. Je to zvláště užitečné, pokud potřebujete psát pomocí Sudo
:
echo some_content | Sudo dd status=none of=output.txt
Kromě Sudo
je to ekvivalent:
echo some_content > output.txt
nebo k tomu:
echo some_content | Sudo tee output.txt > /dev/null