Portál AbcLinuxu, 30. dubna 2025 12:44
Pamatujete si na xkcd komix, kde atomová bomba pro odjištění vyžaduje validní příklad použití taru? Ať ano či ne, v tomto blogu se o nástroji GNU tar dozvíte co už dost možná stejně víte, případně co jste asi ani nechtěli vědět.
Pro připomenutí (přece jen, ten díl vyšel už před pár lety):
Poznámka: pro alt text musíte kliknout na odkaz.
Hned z kraje musím přiznat, že mi tato narážka přišla tak trochu přehnaná. Tohle sice není v rámci vtipu nic divného, ale přece jenom tar nepatří mezi nástroje, jehož volby musím nějak často dohledávat. Možná by se v tomto kontextu lépe vyjímal např. git, ale ten postrádá oproti taru další bombastické asociace (narážka na tar bombu nebo Tsar bombu ), což ho pro potřeby toho vtipu maličko diskvalifikuje.
Na druhou stranu je ale pravda, že když jsem kdysi dávno používal na rozbalování archivů extract
script z Archlinux wiki, používat přímo tar
bych bez man stránky nebo googlení taky nemohl. A přitom, jak jsem později taky zjistil, to není nijak krkolomné
Ve většině případů si vystačím s tím, že tar xf soubor.tar.gz
rozbalí archiv (kde xf
si pamatuji jako extract file), zatímco pro zabalení souboru použiju tar caf soubor.tar.gz soubor
(kde caf
je create archive file) a typ archivu (v tomto případě tar.gz
) tar hádá podle přípony cílového souboru.
Tady se hodí dodat, že i když na strojích, kam mám aspoň ssh přístup, je skoro vždy nainstalován GNU tar implementace taru, je v předchozích příkladech použit pro volby příkazové řádky BSD styl, který z nějakého iracionálního důvodu pro tar preferuju.
Možná je to tím, že v unixovém stylu bych oproti BSD verzi musel psát jeden znak navíc:
tar -caf soubor.tar.gz soubor
a srovnání s GNU stylem snad ani nemá cenu komentovat (btw tady si můžete všimnout jedné drobnosti, a to že jsem v předchožím odstavci trochu kecal, a to a
není od archive):
tar --create --auto-compress --file soubor.tar.gz soubor
Skutečnost ale může být jednodušší na vysvětlení. Ty BSD volby používám dost možná jen proto, že jsem to velmi dávno někde viděl a od té doby to tak pořád dokola ze setrvačnosti používám, anichž bych se na tím nějak extra zamýšlel. A trochu hádám, že tahle, možná trochu náhodná setrvačnost, nebude jenom můj případ.
Podobně můžete různě po internetu vidět ukázky použití taru s písmenky jako z
nebo j
, které určují typ použitého kompresního programu (z
je pro gzip
, j
pro bzip2
). Pokud ale budete chtít použít např. xz
, nevím jestli budete mít radost, až z man stránky zjistíte, že odpovídající jednopísmenková volba je J
. I když na druhou stranu, je to GNU tar ... takže je tam i rozumná dlouhá verze té volby --xz
a díky tomu, že už jim došly písmenka, se žádné další jednoznakové zkratky pro kompresní algoritmy nepřidávají. A přitom výše zmíněná volba auto compress je v GNU tar již skoro 10 let (od verze 1.20 vydané 14. 4. 2008), takže se to už mezitím aktuálně dostalo i do distribucí typu RHEL 6 nebo Debianu oldstable.
Na druhou stranu ale hodně štěstí, pokud byste tuhle GNU fičuru chtěli použít na např. OpenBSD:
$ tar caf archive.tar.gz random.c file1.c
tar: unknown option a
usage: tar {crtux}[014578befHhjLmNOoPpqsvwXZz]
[blocking-factor | archive | replstr] [-C directory] [-I file]
[file ...]
tar {-crtux} [-014578eHhjLmNOoPpqvwXZz] [-b blocking-factor]
[-C directory] [-f archive] [-I file] [-s replstr] [file ...]
A tady se dostáváme k možnosti, že si ten komix dělá dost možná srandu i z toho, jak různé implementace taru (např. výše zmíněná GNU vs OpenBSD) chápou volby příkazové řádky. Proč by na té bombě nemohla běžet nějaká extra stará Linuxová distribuce, FreeBSD nebo snad Solaris? Tuhle možnost bych ale dál dovolil pro potřeby tohoto blogu zanedbat. Konec konců, tento problém mají všechny tradiční unixové nástroje, ne jen tar.
Když se ale na chvíli vrátím k volbám nástroje GNU tar a měl bych vybrat ještě jednu která stojí za zmínku, je to t
neboli --list
, která vypisuje seznam souborů v archivu:
$ tar tf passthrough.tar.xz
Makefile
passthrough.1
passthrough.c
Tím bychom měli výčet command line voleb pro GNU tar, co imho stojí za zapamatování, kompletní. Všechno ostatní hledám v man stránce, která ale dokáže už jen díky samotnému počtu funkcí implementovaných v GNU taru občas překvapit.
Např. nedávno jsem potřeboval vygenerovat checksum ze všech souborů v archivu aniž bych celý archiv rozbaloval (jednak to není nutné a druhak jsem na to ani zrovna neměl volný diskový prostor) a ukázalo se, že tar umožňuje volbou --to-command
specifikovat příkaz, kterému se předá obsah každého jednotlivého rozbaleného souboru na standardní vstup. Takže pomocí wrapper skriptu pro sha1sum
(pro potřeby dalšího příkladu uloženého v ~/bin/tar-sha1-t.sh
):
#!/bin/bash
# see also: man tar, https://unix.stackexchange.com/questions/303667/
echo -n $(sha1sum) | sed 's/ .*$//'
echo " $TAR_FILENAME"
Lze nechat tar přímo vypsat sha1 checksum souborů v archivu:
$ tar xf foo.tar.gz --to-command=~/bin/tar-sha1-t.sh
384dcab2b0e67e940406d1bbfd1b083c61319ce4 foobar.png
e1c272d5abe7d339c4047d76294e7400c31e63b4 README
A nebo se taky může stát, že narazíte na vám dosud neznámou tar fičuru zcela náhodou. Např. v tomto případě jsem nejdřív moc nechápal, co se děje:
$ tar caf ccpp-2018-03-03-23:10:55-3667.tar.gz ccpp-2018-03-03-23:10:55-3667
tar (child): Cannot connect to ccpp-2018-03-03-23: resolve failed
tar: Child returned status 128
tar: Error is not recoverable: exiting now
Proč by jako tar měl komunikovat s někým po sítí na základě jména souboru? Ale po chvíli hledání se ukázalo, že:
An archive name that has a colon in it specifies a file or device on a remote machine. The part before the colon is taken as the machine name or IP address, and the part after it as the file or device pathname, e.g.:
--file=remotehost:/dev/sr0
An optional username can be prefixed to the hostname, placing a @ sign between them.
A pokud se vám to nelíbí, tak GNU tar nabízí volbu:
--force-local
Archive file is local even if it has a colon.
Takže následující příkaz již funguje bezvadně:
$ tar --force-local -caf ccpp-2018-03-03-23:10:55-3667.tar.gz ccpp-2018-03-03-23:10:55-3667
Ale pokud se takový archiv pokusíte přečíst a zapomenete na tu dvojtečku, opět máte problém:
$ tar tf ccpp-2018-03-03-23\:10\:55-3667.tar.gz
tar: Cannot connect to ccpp-2018-03-03-23: resolve failed
Ať žijí rozumné výchozí volby a zpětná kompatibilita. Schválně jsem se musel podívat, jak dlouho tam tohle chování je a v NEWS souboru jsem našel:
Version 1.11 - Michael Bushnell, 1992-09.
Version 1.10.16 - 1992-07.
Version 1.10.15 - 1992-06.
Version 1.10.14 - 1992-05.
Version 1.10.13 - 1992-01.
* Remote archive names no longer have to be in /dev: any file with a
':' is interpreted as remote. If new option --force-local is given,
then even archive files with a ':' are considered local.
Upřímně nechápu, jak tohle někomu přišlo jako rozumný nápad, ale asi mi chybí historický kontext. A asi není ani třeba dodávat, že tar z OpenBSD tohle neimplementuje.
Důležitý detail, který jsem zatím vynechal je, jakým protokolem se tar chce na vzdálený stroj připojit:
By default, the remote host is accessed via the rsh(1) command. Nowadays it is common to use ssh(1) instead.
Takže dneska už ssh, což si můžete sami zkusit na vhodně pojmenovaném tarballu:
$ tar tf localhost:foo.tar.gz
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:TgLgqk9xkWb2oGtBRgk1vKPvWzbgdkp0InR0PZHXnbQ.
ECDSA key fingerprint is MD5:48:16:9c:eb:b8:22:0f:ab:22:b4:71:a5:3e:54:2c:7f.
Are you sure you want to continue connecting (yes/no)?
To už možná stojí za úvahu, zda takové chování není natolik podivné, že by se dalo považovat do jisté míry za bezpečnostní problém. Např. by šlo pojmenovat tarball tak, že při pokusu o jeho rozbalení vás UPC odpojí nebo by šlo pokusit se o deanomizaci nepozorného uživatele tor sítě. Ale oba ty příklady jsou víc absurdní než praktické.
O něco lepší by bylo např. nachystat na vzdáleném serveru tarball s jiným obsahem, který by si oběť nevědomky stáhla a rozbalila místo skutečného obsahu tarballu - teda za předpokladu, že nikomu nebude divné, že v názvu tarballu je vaše doména a název souboru, že odhadnete jaký login oběť používá, že budete mít ssh public key oběti a že oběť buď pro tento ssh klíč nepoužívá heslo nebo jej má v cache ssh agenta a k tomu všemu by bylo taky dobré, aby fingerprint vašeho ssh serveru oběť už měla mezi known hosts nebo ještě lépe, aby bylo toto ověřování zcela vypnuté. Něco málo z toho by mohl usnadnit github a jeho automatické zveřejňování public ssh klíčů ... ale to už si připadám jako v jiném xkcd komixu, jen místo příběhu s hackováním regexpů v perlu na laně dosaďte tento odstavec (I know GNU tar colon hack!), je to asi tak stejně praštěné:
Nicméně, vážně to funguje:
$ cd ~/tmp
$ touch good-file bad-file
$ tar caf bad.tar.gz bad-file
$ tar --force-local -caf localhost:bad.tar.gz good-file
$ cp bad.tar.gz ~
$ tar tf localhost:bad.tar.gz
bad-file
$ tar --force-local -tf localhost:bad.tar.gz
good-file
Opačná varianta, kdy někomu poradíte jak "správně" pojmenovat tarball aby pak posléze nahrál data na váš server je asi taky možná, ale ještě uhozenější.
Takže ve výsledku tohle nevypadá použitelně ani jako kanadský žertík ... možná snad kdyby byl někdo extra šikovný při vymýšlení a nasazování shell skriptu používajícího tar, ale i to mi přijde dost nepravděpodobné :)
Pokud jsem někoho snad inspiroval k nahlédnutí man stránky pro GNU tar, nebo ještě lépe k prostudování GNU tar dokumentace, nechť se podělí v komentářích o jeho oblíbenou funkcionalitu.
Tiskni
Sdílej:
ta věc s dvojteckouPff. Keby len tar. Skús obyčajný bash:
cat < /dev/tcp/cygnus-x.net/17
cat < /dev/tcp/alpha.mike-r.com/17
Pěkné :-) Myslel jsem, že na takovéhle věci potrpí jen Plan 9 nebo GNU Hurd :-)
$ ls -l /dev/tcp
ls: cannot access '/dev/tcp': No such file or directory
$ ls -l /dev/tcp/localhost/22
ls: cannot access '/dev/tcp/localhost/22': No such file or directory
$ cat /dev/tcp/localhost/22
cat: /dev/tcp/localhost/22: No such file or directory
$ cat < /dev/tcp/localhost/22
SSH-2.0-OpenSSH_7.6
^C
Pravda. A když si to vytvořím jako soubor, tak se to chová odlišně podle toho, jestli to čtu jako soubor nebo přesměrovávám:
$ cat /dev/tcp/localhost/22 ahoj $ cat < /dev/tcp/localhost/22 SSH-2.0-OpenSSH_7.5p1 Ubuntu-10ubuntu0.1
jj, je to specifické pro Bash:
$ dash -c 'cat < /dev/tcp/localhost/22' ahoj $ bash -c 'cat < /dev/tcp/localhost/22' SSH-2.0-OpenSSH_7.5p1 Ubuntu-10ubuntu0.1
A v dokumentaci jsou i příklady, jak s takovým spojením pracovat a používat třeba HTTP.
ale přece jenom tar nepatří mezi nástroje, jehož volby musím nějak často dohledávat.no jestli z fleku vite, kam napsat exclude, tak jste frajer. Ja si to musim vzdycky vygooglit.
Nicméně nedávno se mi podařilo rozjet starý kazeťák. Marně jsem pátral jak se na něj vlastně (t)ape (ar)chive používá. Škoda že už je to jen jméno.
To je trochu jiný "kazeťák". :-)
Není to jen jméno. Když se podíváte, jak ten formát vypadá, je na něm vidět, že původně byl určen pro archivaci na pásku, která není seekovatelná. Proto tam např. není žádný "index", který by vám umožnil jít rovnou na konkrétní soubor, ale musíte archiv vždy procházet sekvenčně (práci si lze ušetřit jen v tom, že na seekovatelném zařízení lze skákat po hlavičkách).
Hádám, že pásková jednotka má nějaké digitální rozhraní (SCSI, paralelní port), zatímco magnetofon analogový výstup. Což ale pravda neznamená, že by na magneťák nešlo ukládat data (viz domácí 8 bitové počítače).To začalo až pozděj, ale v době existence UNIXu byl standard KCS.
Každopádně ta Tesla SP 210 vypadá spíš jako kazeťák pro ty osmibity než jako pásková jednotka. Co jsi s tím zkoušel dělat?Ano je to kazeťák (konkrétně pro 8-bit). A co jsem zkoušel? No uložit na to nějaké data, co jiného (viz příloha).
akže nevím jak se nejlíp data zaznamenávají, ale mělo by stačit přimo magnetizovat jedním nebo druhým směrem ne? (tedy dva stavy)Tak to mají kazety, magnetické pásky i ty diskety. Liší se to pouze požitým schématem (PWM, FM, MFM, M²FM, GCR) resp. jejich efektivitou.
A šlo ti to z toho kazeťáku i zpětně přečíst?Samozřejmě. Proč by nemělo? Tohle je právě výhoda staré klasické PWM (nebavím se o Turboloaderech). Ono se na tu kazetu nevleze ani Megabajt nicméně to většinou přežije (pravděpodobně i termonukleární válku). Mám kazety staré přes 30let, furt fungují jako kdysi. Jenže vždycky je to omezeno rychlostí CPU (což bylo závratných 3.5 MHz) proto jsem pátral po tom jestli neexistuje něco efektivnějšího. Ona i spektrální analýza odhalí že o moc efektivně uloženo není (viz spektrum v příloze).
Asi existuje spousta různých historických nástrojůNo právě že ani moc ne. Ono to bylo i v UNIXu implementované v /dev/tape a ne v žádném nástroji.
tak bych se na ně asi vykašlal a zkusil ten výše zmíněný minimodemYup přesně tak. Teň s ním testuju BASICODE ale popravdě mi to moc nefunguje ani v tom emulátoru ani v tom mimimodemu
ps
. Kde je to ještě vylepšené tím, že stejné písmeno má jiný význam v BSD a jiný v Unix notaci.
Většinou ps aux
. A zrovna u výpisu procesů by se hodilo nejlíp SQL (projekce + restrikce – vybrat si jaké sloupce chci + filtrovat podle různých kritérií).
A zrovna u výpisu procesů by se hodilo nejlíp SQL (projekce + restrikce – vybrat si jaké sloupce chci + filtrovat podle různých kritérií).Na kriteria mas bud prepinace nebo grep, na vyber sloupcu prepinac "-o".
A zrovna u výpisu procesů by se hodilo nejlíp SQLSQL je spatny jazyk i na praci s relacnimi daty, pouzivat ho na cokoliv jineho mi proto neprijde jako prilis moudry napad. Koncepcne cistejsi mi prijde spis pristup, ktery pouziva Powershell.
ps -o
a awk
.
Projekce se udělá přes to ps -o
. Např. pro vypsání pidu, název procesu a jeho rss pro všechny procesy:
$ ps -e --no-headers -o pid,comm,rss,size
1 systemd 11704 20656
2 kthreadd 0 0
4 kworker/0:0H 0 0
6 mm_percpu_wq 0 0
..... vynecháno ................
6249 kworker/2:0 0 0
6266 kworker/1:0 0 0
6273 kworker/3:0 0 0
6290 ps 1736 1040
6291 less 1020 356
Selekce se nelíp řeší přes awk
. Např. pokud chci z předchozího příkladu vyfiltrovat jen processy co mají v názvu tmux, rozpoznané dle regexpu:
$ ps -e --no-headers -o pid,comm,rss,size | awk '$2 ~ "tmux"'
2004 tmuxp 19072 11928
2011 tmux: server 3732 884
2487 tmux: client 3300 492
Nebo jen bash procesy, jejichž rss je větší než 10700:
$ ps -e --no-headers -o pid,comm,rss,size | awk '$2 == "bash" && $3 >= 10700'
1962 bash 10768 7544
3933 bash 10940 7544
4731 bash 10708 7464
5472 bash 10824 7544
BTW: v roce 2014 jsem dělal prototyp, SQL API k OS (zdrojáky).
Pro psaní ad-hoc dotazů je to SQL trochu robustní a člověk spíš použije ten grep/awk, spokojí se s nedokonalým výsledkem, ale pro psaní skriptů nebo něčeho, co má běžet bez dozoru se hodí mít spolehlivější nástroj, který se nikdy nesplete např. v tom, kde jsou hranice1 mezi sloupci/atributy, a v kterém jde psát ty dotazy přehledně, čitelně, bez kryptických zkratek/parametrů.
[1] v textovém výstupu je to většinou mezera nebo jiný oddělovač, ale moc se nepočítá s tím, že by znak mezery či oddělovače mohl být i součástí hodnoty a escapování buď neexistuje nebo není na jedné či druhé straně podporované; složitější strukturovaná data a stromy taky není jak vyjádřit
Většinou ps aux.+1 A vždycky jsem si myslel, že to používám proto, že to takto zmiňoval Cliff Stoll v knize Kukaččí vejce, který byl zvyklý na BSD. Ale když jsem to teď hledal, ukázalo se že je tam
ps -aux
...
Nicméně ten kontext, v kterým to bylo zmíněno, se do této debaty celkem hodí:
Ze zvyku jsem psával ps -aux, ta tři poslední písmenka říkala otci Unixovi, aby sdělil status jednoho každého. Vetřelec ale napsal ps -eafg. Podivné. Nikdy jsem neviděl nikoho použít příznak g.A o stránku dál:
„Cliffe, ten hacker není z Berkeley“ „Jak to víš?“ „Tys viděl toho chlápka vypsat příkaz ps -eafg, že?“ „Jo, tady je výpis,“ opáčil jsem. „Obyčejný unixovský příkaz k vypsání seznamu všech aktivních procesů ‚ps‘ znamená print status, a ta čtyři písmenka zmodifikují displej. Je to svým způsobem něco jako přepínače na stereu, mění se způsob, jak příkaz funguje.“ „Cliffe, já vím, že jsi zvyklý na Berkeley Unix. Od té doby co ho vymysleli, píšeme mechanicky ‚ps‘, když chceme vidět, co se děje v systému. Ale řekni mi, co modifikují ta čtyři písmena?" Dave věděl, že v obskurních příkazech Unixu jsem ignorant. Tvářil jsem se sebevědomě. „No, příznak e znamená vypsat jméno procesu i prostředí, a příznak a vypíše všechny procesy - nejenom tvoje. Hacker tu chtěl vidět všechno, co na systému běží.“ „Dobrý, to je půlka. A na co jsou ty příznaky f a g?“ „Nevím.“ Dave mě v tom nechal plácat, dokud jsem nedoznal svou nevědomost. „G-výpis žádáš, když chceš vidět zajímavé i nezajímavé procesy. Ukáže se všechno, i nezajímavé procesy, jako je účetnictví. A všechny ukryté procesy.“ „A víme, že se nám šťoural v účetních programech.“ Dave se usmál: „A tak nám zůstává f. Jenže to už není Berkeley Unix. To je metoda AT&T Unixu. Berkeley Unix dává na seznam všechny procesy automaticky, takže přepínač f nepotřebuje. Náš přítel nezná Berkeley Unix. Je ze staré unixovské školy.“
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.