Nesprávným použitím této zástupné karty Linuxu riskujete ztrátu dat
Zástupné znaky Linuxu umožňují zadat jeden příkaz, který působí na celé skupiny souborů současně. To je skvělá úspora času, pokud se něco nepokazí. A mohou. Destruktivně.
K čemu jsou zástupné znaky
Známé zástupné znaky jsou otazník, ?, a hvězdička, *. Ty lze použít k vytvoření vzorů souborů. Otazník představuje libovolný jednotlivý znak a hvězdička představuje libovolnou posloupnost znaků, včetně nula znaků.
Když to víme, můžeme vytvořit vzory, které odpovídají více názvům souborů. Namísto psaní všech názvů souborů na příkazovém řádku napíšeme vzor. Všechny soubory, které odpovídají vzoru, jsou ovládány příkazem.
Pokud máme kolekci souborů v adresáři, jako je tento:
Můžeme vybrat skupiny souborů, které odpovídají vzorům, které poskytujeme.
ls taf_*
To nám dává všechny soubory, které mají na začátku názvu „taf_“.
ls *.sh
ls s*.sh
První příkaz vypíše všechny soubory skriptů shellu v adresáři. Druhý příkaz uvádí pouze soubory začínající na „s“, které jsou také soubory skriptů shellu.
To vše vypadá dost jednoduše a s ls to tak je. Tento typ porovnávání vzorů však mohou využívat i jiné příkazy. Problémy nastanou, když se shell pokusí pomoci porovnáváním vzorů, než dostane příkaz šanci.
Použití hvězdičky s příkazem find
Akce rozšíření vzoru do seznamu odpovídajících souborů se nazývá globbing.
Začalo to jako samostatný příkaz v Unixu verze 6, pak se stal knihovnou, kterou bylo možné propojit s jinými programy, a dnes je to vestavěný shell. Rozbalení vzoru provádí shell a výsledky rozbalení jsou předány příkazu jako parametry příkazového řádku.
Podíváme se na dva příklady pomocí příkazu find. Jeden dělá to, co byste očekávali, ale druhý vás může překvapit.
V tomto příkladu použijeme adresář s jediným souborem, který se nazývá readme.txt. Existují dva adresáře, src a inc. Obsahují mix souborů C, H, MD a TMP.
ls -R
Můžeme použít find k rekurzivnímu vyhledání souborů (-type f) s názvy, které odpovídají našemu vzoru (-name *.c), čímž získáme seznam souborů C.
find . -type f -name *.c
Můžeme přidat možnost -not, která invertuje vyhledávání a zobrazí nám vše kromě souborů C.
find . -type f -not -name *.c
Po zkontrolování tohoto seznamu jsme se rozhodli smazat vše kromě souborů C. Můžeme to udělat přidáním volby -delete.
find . -type f -not -name *.c -delete
find .
Druhý příkaz find rekurzivně vypíše vše v aktuálním adresáři a pod ním. Zbývají pouze naše soubory C.
To fungovalo tak, jak by většina z nás očekávala. Nyní uděláme přesně to samé, ale tentokrát soubor v aktuálním adresáři není textový soubor, je to soubor C.
ls -R
K odstranění všeho kromě souborů C použijeme stejný příkaz find a možnosti. To jsme vůbec nechtěli.
find . -type f -not -name *.c -delete
find .
To bezstarostně smaže každý jednotlivý soubor ve stromu adresářů, kromě jednoho souboru C v aktuálním adresáři.
Soubory ještě jednou resetujeme a zadáme příkaz tak, jak jej máme používat.
Všechny soubory jsou na svém místě a v aktuálním adresáři máme soubor C, stejně jako předtím.
ls -R
Tentokrát zabalíme zástupný vzor do jednoduchých uvozovek.
find . -type f -not -name '*.c' -delete
find .
To jsme chtěli. Všechno je pryč kromě našich souborů C.
OK, tak co se pokazilo?
Jednoduché uvozovky brání shellu v rozšiřování vzoru názvu souboru. Je předán příkazu nebo programu tak, jak je, aby příkaz mohl jednat.
V příkladu, který fungoval, jsme měli v aktuálním adresáři soubor readme.txt. Shell nenašel shodu s *.c, takže přešel *.c, aby našel, podle čeho se má jednat.
V příkladu, který odstranil vše kromě souborů C, jsme měli v aktuálním adresáři soubor s názvem main.c. Shell porovnal vzor s tímto souborem a předal název souboru příkazu find. Instrukce find tedy byly smazat vše, co se nejmenovalo main.c.
Můžeme to ilustrovat na malém programu v jazyce C, který nedělá nic jiného, než že zobrazuje parametry příkazového řádku v okně terminálu.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
printf("You supplied %d arguments.\n", argc-1);
for (i=1; i<argc; i++)
printf("%-2d) \"%s\"\n", i, argv[i]);
exit (0);
}
Uložil jsem to jako soubor s názvem glob.c a zkompiloval jsem jej pomocí:
gcc -o glob glob.c
Proměnná argc obsahuje počet argumentů, které předáme programu. Cyklus for prochází seznamem argumentů a každý z nich vytiskne do okna terminálu.
Cyklus for začíná argumentem jedna, nikoli nulou. Existuje argument nula. Vždy nese název samotné dvojhvězdy. Abych zabránil zakalení vody, vyhnul jsem se tisku. Jediné argumenty, které se vytisknou, jsou ty, které poskytujeme na příkazovém řádku.
./glob one two 3 ant beetle cockroach
Zkusme to s *.c jako parametrem příkazového řádku.
ls *.c
./glob *.c
Bez jakýchkoli souborů C v aktuálním adresáři předá shell *.c příkazu find. Příkaz find pak působí na samotný vzor zástupných znaků. Ale když máme soubor C v aktuálním adresáři, shell předá programu název odpovídajícího souboru C.
ls *.c
./glob *.c
Náš program přijímá jako parametr název souboru C a totéž platí pro příkaz find. Takže vlastně find dělal to, co měl dělat: smazal všechny soubory kromě souboru main.c.
Tentokrát zabalíme zástupný vzor do jednoduchých uvozovek.
ls *.c
./glob '*.c'
Shell ignoruje možnost použít svůj globbing na vzor zástupných znaků a předá jej přímo příkazu k dalšímu zpracování.
Jednoduchá oprava, můžete mě citovat
Jako obecné pravidlo uvádějte vzory zástupných znaků, které předáváte příkazům jako find. To je vše, co je potřeba k tomu, aby se zabránilo tomuto typu potenciálně katastrofální nehody.