Portál AbcLinuxu, 31. července 2025 15:26


Dotaz: Expanze * v příkazu rm

28.1.2017 13:35 miro
Expanze * v příkazu rm
Přečteno: 536×
Odpovědět | Admin
Potřebuji ve skriptu použít (navíc pod rootem) něco jako rm -rf /muj/adresar/* ; něco se mi ale plete, že jsem kdysi dávno četl něco o tom, že ta hvězdička by mohla být interpretována mimo jiné jako .. . Takže by rm -rf /muj/adresar/* mohlo dopadnout jako rm -rf /muj/adresar/../../../* Týkalo se to jen nějaké speciální situace, nepamatuji si to přesně, nejsem schopen dohledat, kde jsem to četl a nemám teď ani k dispozici žádný virtuál, na kterém bych si to mohl vyzkoušet. Existuje to nebezpečí expanze na .. vůbec? A jde rm -rf /muj/adresar/* po stromu pouze směrem dolů?

Řešení dotazu:


Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

28.1.2017 14:51 NN
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Odpovědět | | Sbalit | Link | Blokovat | Admin
Asterisk '*' na nadrazeny adresar '..' nexpanduje.
28.1.2017 15:33 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Odpovědět | | Sbalit | Link | Blokovat | Admin
Proč tam cpete to -f? Víte, co to dělá, nebo to jen odněkud opisujete?

Kombinace -r a * je také zvláštní. Protože to dělá docela specifickou věc, a pochybuju, že zrovna to je vaším cílem.

Na co se expanduje hvězdička se dočtete v manuálu k vašemu shellu. Např. v bashi se při standardním nastavení hvězdička neexpanduje na názvy začínající tečkou (takže ani na . nebo ..) a na názvy obsahující lomítko. Takže příkaz rm -r /muj/adresar/* se expanduje na všechny viditelné (nezačínající tečkou) soubory a adresáře v /muj/adresar/ a díky parametru -r je rm rekurzivně smaže. Nebo-li vám v /muj/adresar zůstanou všechny skryté soubory a adresáře (na první úrovni). Problém ještě můžou způsobit soubory a adresáře, jejichž název začíná pomlčkou, protože je rm bude chápat jako parametr. Proto lze použít parametr -- (dvě pomlčky), po něm už bude rm vše chápat jako název souboru.

Pokud chcete smazat adresář /muj/adresar a vše, co je uvnitř, je na to jednoduchý příkaz:
rm -r /muj/adresar
Jendа avatar 28.1.2017 15:36 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Pokud chcete smazat adresář /muj/adresar a vše, co je uvnitř
Tipuji, že chce smazat obsah a adresář nechat. (a vytvořit ho po smazání není jednoduché, pokud potřebuje zachovat práva a extended atributy)
28.1.2017 21:11 miro
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Ano, potřebuji smazat natvrdo veškerý obsah adresáře a adresář zachovat. Důvod je ale jiný - ten adresář je mountpointem a bude odstraněn až po umountu.
28.1.2017 21:20 miro
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
-f - no, byl jsem přesvědčen, že vím, ale nevěděl jsem. Myslel jsem si, že to smaže soubory, u kterých by to jinak řvalo, že je používá jiný proces. A nevím, jak se k takové situaci rm staví, v man rm jsem o tom nic nenašel. Takže rm -r -- /muj/adresar/* je správně?
28.1.2017 21:37 miro
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm

Ne, tak ještě jinak:

rm -rf -- /muj/adresar/*
rm -rf -- /muj/adresar/..?*
rm -rf -- /muj/adresar/.[!.]*

???

28.1.2017 21:43 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Raději
find /muj/adresar -mount -delete
28.1.2017 21:39 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
A nevím, jak se k takové situaci rm staví, v man rm jsem o tom nic nenašel.
K tomu se nijak nestaví rm, k tomu se staví unix. A to tak, že na jeden soubor existuje jeden či více odkazů. Vytvoříte pojmenovaný soubor v souborovém systému – vznikne první odkaz. Vytvoříte na soubor odkaz (ln) – vznikne druhý odkaz. Nějaký program otevře soubor pro čtení – vznikne třetí odkaz. rm smaže jen ten pojmenovaný odkaz v aktuálním adresáři – ale soubor se fyzicky smaže až tehdy, když přestanou existovat všechny odkazy. Tedy když smažete ostatní odkazy na souborovém systému a soubor uzavřou všechny programy, které ho mají otevřený.
Takže rm -r -- /muj/adresar/* je správně?
Je to lepší, ale nesmaže vám to skryté (začínající tečkou) soubory a adresáře přímo v /muj/adresar. Pokud víte, že tam nejsou a nikdy nebudou, můžete to použít takhle. A také pokud víte, že tam souborů a podadresářů nebude moc – přeci jen existuje nějaký limit na počet argumentů příkazu. Pokud to chcete mít obecné, použijte find, ten si poradí i se skrytými soubory i s jejich velkým množstvím, a jako bonus bude fungovat i při jiném nastavení expandování žolíků v shellu.
28.1.2017 22:31 miro
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
ale soubor se fyzicky smaže až tehdy, když přestanou existovat všechny odkazy

A co když nějaký soubor má otevřený ten soubor a jiný proces nejenže ten soubor smaže z toho adresáře, ale podtrhne mu mountpoint, ve kterém ten soubor byl? Připadne mi, že ten proces musí pracovat spíš s nějakou kopií dat než jen s odkazem na ten soubor, jinak by o ta data musel odmountováním nutně přijít, ne?

Jinak za find díky. Je trochu škoda, že skončí exitstatusem 1, protože /muj/adresar/ se mu nepovede smazat, což může být trošku otrava, pokud by chtěl člověk testovat, jestli se mazání podařilo, ale pro moje účely to takhle bohatě postačí.

Jendа avatar 29.1.2017 01:05 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
ale podtrhne mu mountpoint, ve kterém ten soubor byl
FS s otevřeným souborem nejde odmountovat. Zkus si třeba umount /home (pokud ho máš na zvláštním FS).
29.1.2017 09:14 miro
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Aha, jde to jen s parametrem -l. Ale ten odkaz tam zřejmě zůstane do ukončení práce s tím souborem.
29.1.2017 14:05 Peter Golis | skóre: 65 | blog: Bežné záležitosti | Bratislava
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Áno. Od toho je "Lazy unmount".
Jendа avatar 29.1.2017 01:06 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Jinak za find díky. Je trochu škoda, že skončí exitstatusem 1, protože /muj/adresar/ se mu nepovede smazat
-mindepth 1 nepomůže?
29.1.2017 09:15 miro
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Jo, to je to pravé ořechové, díky.
28.1.2017 19:41 Jooky (inactive) | skóre: 39 | blog: Jooky | Bratislava
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ta konstrukcia "rm", co si napisal ma vzasade dva problemy:

1) "hviezdicka" sa ti moze expadnut na nazvy, ktore budu inac interpretovane, ako ocakavas:
$ rm *
rm (GNU coreutils) 8.25
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Paul Rubin, David MacKenzie, Richard M. Stallman,
and Jim Meyering.
$ ls -l
total 0
-rw-rw-r-- 1 lukas lukas 0 Jan 28 19:30 --version

2) z pohladu pocitaca je celkom dlhy cas medzi vytvorenim zoznamu a samotnym "mazanim" suborov prikazom rm. Tento cas moze nejaky zaskodnik vyuzit na to, aby podhodil rm na vymazanie nieco uplne ine ...

Najlepsie je na "rm" v scriptoch zabudnut a pouzit radsej konstrukciu find ... -delete. Samotny find robi viacero kontrol, pred samotnym mazanim (aby zabranil problemu s race condition) a ako bonus si mozes nechat pekne vypisovat subory, ktore mazes. Napr. ja pouzivam toto na pretriedenie fotiek z bezpecnostnej kamery.
find /data/www/motion/cam1 -xdev -type f -mtime +22 -ls -delete
Cez -mindepth a -maxdepth sa da pekne doladit ako hlboko ma hladat veci na zmazanie (a napr nechat directory a zmazat len obsah).
Jendа avatar 28.1.2017 19:54 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Tento cas moze nejaky zaskodnik vyuzit na to, aby podhodil rm na vymazanie nieco uplne ine ...
Tady by mě zajímal příklad.
30.1.2017 20:00 Jooky (inactive) | skóre: 39 | blog: Jooky | Bratislava
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
otvorene poviem, ze neviem ktore z veci uz opravili a nejak som tuto tematiku uz dlhsie nesledoval. Vacsina race condition vychadzala z toho, ze zoznam sa vacsinou robi cez shell expanziu a rm prechadza strom, ktory maze, cez ekvivalnet "cd".

1) ked mame napr /tmp/a/b/c, tak rm sa najprv cez chdir dopracuje az do "c" a nasledne potom cez chdir("..") posuva "hore". Ked pocas vymazavania veci v "c" tento dir presunieme rovno do /tmp, tak sa rm cez chdir("..") dopracuje az do "/" a ... zacne secko mazat tam :D

2) dalsia zloba je, ked napr v /tmp je "dir". Ked v spravnom momente ten dir zmenime za linku, tak rm dokazeme "poslat" niekde inde.

skus si na googli pohladat rm a race condition urcite najde aj viacej chutoviek :)
30.1.2017 21:26 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Odpovědět | | Sbalit | Link | Blokovat | Admin

Zaprvé, nic se neexpanduje v příkazu rm. Jediné, co v tomhle případě expanduje hvězdičky, je shell. (Snad jediný z běžných příkazů, který opravdu dostává hvězdičky (které se pak musí v shellu escapovat) a sám je expanduje, je find. Ostatní příkazy zpravidla nic neexpandují a používají přesně ty parametry, které jim předá shell.)

Zadruhé, proč to prostě nezkusíš pomocí echo, jen tak se podívat, co přesně shell tomu příkazu rm předává?

echo rm -rf /můj/adresář/*
K expanzi bych doplnil, že (samotná) hvězdička v shellu implicitně ignoruje soubory a adresáře, jejichž název začíná tečkou. Tedy například ., .. a cokoliv jiného s tečkou na začátku, třeba .profile. Zkus porovnat tři následující příklady:
cd ~
echo *         # Všechno, co nezačíná tečkou
echo * .[^.]*  # Úplně všechno, kromě . a ..
echo * .*      # A s tímhle fakt opatrně!
30.1.2017 21:47 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Zadruhé, proč to prostě nezkusíš pomocí echo, jen tak se podívat, co přesně shell tomu příkazu rm předává?
V zsh lze expandovat rovnou pomocí tabulátoru. Takže si například můžete nechat hvězdičku expandovat a pak seznam ještě ručně upravit.

A s tím expandováním je to také různé podle shellu. zsh při expanzi implicitně negeneruje názvy s tečkou na začátku ve všech případech (tj. nejen u hvězdičky, ale i u jiných expanzí), a . a .. negeneruje při expanzi nikdy.
30.1.2017 21:56 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
…zsh při expanzi implicitně negeneruje názvy s tečkou na začátku ve všech případech (tj. nejen u hvězdičky, ale i u jiných expanzí)…

Tohle tvrzení je mírně zavádějící, protože .* nebo .[^.]* v zsh generují také soubory a adresáře s tečkou na začátku.

A ano, .* a .[^.]* dávají v zsh totéž, což je odlišnost od bashe. (Toho jsem si až doteď nevšiml — zajímavé poučení.)

Celkem bezpečná varianta je tedy .[^.]* — na té se totiž shodne bash i zsh.

31.1.2017 07:09 Filip Jirsák | skóre: 68 | blog: Fa & Bi
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
Ano, napsal jsem to špatně. Zástupné znaky se neexpandují na názvy s tečkou na začátku nebo za lomítkem, pokud není tečka explicitně uvedena na začátku nebo za lomítkem ve vzoru. Chtěl jsem upozornit na to, že v zsh je to pravidlo univerzální, netýká se jen hvězdičky ale všech expanzí.
30.1.2017 22:03 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm
echo * .[^.]*  # Úplně všechno, kromě . a ..

Určitě? :-)

31.1.2017 04:11 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm

Ano, ... tam nebude.

31.1.2017 04:14 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Expanze * v příkazu rm

Že by tedy * .[^.]* ..?*? No, někdo asi zase vymyslí protipříklad, ale co už.

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.