Šest testovacích vzorů, které skutečné Bash skripty opravdu používají
Bash a další shelly, jako zsh, podporují několik testovacích operátorů, které můžete použít ke kontrole podmínek: například zda něco je soubor, nebo zda je jedno číslo větší než jiné. Tyto testy jsou velmi užitečné a pravděpodobně se objeví ve většině shell skriptů, které napíšete.
Objevte, jak používat tyto operátory na příkladech ze skutečných shell skriptů.
-f pro kontrolu, zda existuje běžný soubor
Operátor -f kontroluje, zda daná cesta k souboru vede k běžnému souboru, nebo ne, a je to jeden z nejvíce užitečných operátorů, na které narazíte. Můžete ho použít v podmíněném bloku s touto strukturou:
if [ -f file ]
then
echo true
else
echo false
fi
Například:
if [ -f /bin/ls ]; then echo 0; else echo 1; fi
Tato kratší verze (užitečná pro testování) přímo vypíše výsledek testu:
[ -f /bin ]; echo $?
Ve skriptu je často pohodlné používat booleovské operátory místo konstrukce if. Pamatujte, že příkaz [ (test) je stále potřeba k vyhodnocení podmínky:
[ -f /bin/ls ] && echo "It's all OK, we can run ls"
Jedním z běžných použití této kontroly je načtení konfigurace ze souboru, který nemusí existovat:
[ -f CONFIG-FILE ] && . CONFIG-FILEDalší použití vám umožňuje vytvořit soubor s unikátním názvem, takže se můžete vyhnout neúmyslnému přepsání existujících dat:
while [[ -f $filename ]]; do
filename=${filename%.html}$RANDOM.html
done
Když se tato smyčka dokončí, proměnná filename bude obsahovat název, který ještě neexistuje. RANDOM je speciální shellová proměnná, která při každém přístupu vrací jinou hodnotu.
Toto není nejlepší způsob, jak vytvářet náhodné hodnoty. Pokud chcete vytvořit dočasný soubor a nezáleží vám na jeho umístění, zvažte použití mktemp.
-d pro kontrolu, zda se jedná o adresář
Operátor -d testuje svůj operand souboru, zda jde o adresář. Pokud takový soubor neexistuje, nebo pokud nejde o adresář, -d vrátí false.
Mnoho skriptů vytváří soubory v adresáři při transformaci vstupních souborů nebo generování obsahu. Například tar -C directory způsobí, že tar archivuje soubory z daného adresáře nebo je do něj rozbalí. Pokud děláte něco podobného ve svých vlastních skriptech, můžete zkontrolovat, zda daný adresář existuje:
if [ ! -d "$OUTPUT_DIR" ]
then
mkdir -p "$OUTPUT_DIR"
fi
Tento příklad vytvoří adresář, pokud neexistuje, ale chování vašeho programu se může lišit. V tomto případě to není přísně nutné, protože mkdir -p existující adresář tiše ignoruje. Přesto je to dobrá praxe a kontrola vám dává možnost protokolovat nebo vyvolat chybu, pokud je to potřeba.
Další běžný případ použití tohoto operátoru je téměř opak: vyčištění všech adresářů, které mohl váš skript vytvořit. Například pokud používáte cache adresář pro dočasné ukládání souborů, můžete jej občas nebo na vyžádání vyprázdnit:
if [[ -d "$HOME/.cache/myscript" ]]; then
rm -rf "$HOME/.cache/myscript" 2> /dev/null || true
fi
V jednom ze svých vlastních shellových funkcí používám operátor -d k ověření obsahu své proměnné prostředí PATH:
echo $PATH | tr ':' '\n' | while read tmppath; do
if [ ! -d "$tmppath" ]; then
echo "bad PATH: dir does not exist: $tmppath" >&2
fi
done
-n pro kontrolu řetězce s nenulovou délkou
Operátor -n vrací true (0), pokud je jeho operand neprázdný řetězec, jinak vrací false (1). Jelikož pevný řetězec vždy vrací stejnou hodnotu, obvykle se používá s proměnnou. Můžete jej použít takto:
if [[ -n $var ]]
then
echo "non-empty"
else
echo "empty"
fi
Tento operátor vrátí hodnotu true pro nedefinovanou proměnnou, protože takové proměnné se vždy vyhodnocují jako prázdný řetězec.
Můžete použít -n v kombinaci s kódem, který závisí na tom, že proměnná má nějakou hodnotu. Například velmi častým případem je kontrola shellu, zda lze použít určitou rozšířenou funkcionalitu. Shell zsh nastavuje proměnnou prostředí ZSH_VERSION, takže tato funkce kontroluje, zda je používán zsh:
shell_is_zsh() {
[ -n "${ZSH_VERSION-}" ]
}
-z pro kontrolu prázdného řetězce
Operátor -z je jednoduše opakem -n; kontroluje prázdný řetězec. Vzhledem k tomu, že můžete použít operátor ! pro obrácení podmínky, -z není striktně nutný. Kód, který ho používá, lze vždy přepsat, například:
if [[ -z $var ]]; then ...
Tento kód lze napsat také s použitím -n, takto:
if [[ ! -n $var ]]; then ...
Nicméně, -z je stále užitečné, protože činí záměr jasnějším a zajišťuje lepší konzistenci mezi řadou testů. Podmínka může být užitečná pro předčasné ukončení funkce nebo skriptu v případě, že chybí požadovaná hodnota:
login() {
[[ -z $user_name && -z $user_password ]] && return 1
# more code from here down to implement the actual login process
}
-x pro kontrolu spustitelného souboru
Operátor -x určuje, zda soubor může aktuální uživatel spustit. To zahrnuje kontrolu spustitelného bitu souboru.
Ve svém skriptu můžete použít -x, pokud potřebujete spustit externí program, například:
[ -x "./myscript.sh" ] || echo "Missing execute permissions!"
Obvykle nebudete muset kontrolovat standardní příkazy, i když může být užitečné je kombinovat s command pro běžné programy, které mohou být nainstalovány nebo nemusí být, například:
if [ -x "$(command -v git)" ]; then
echo "Git is installed and ready."
else
echo "Please install Git."
exit 1
fi
Zde se "$ (command -v git)" rozšíří na celou cestu ke příkazu git, jak ji váš shell vyřeší pomocí PATH. Pokud je to prázdný řetězec nebo aktuální uživatel nemá oprávnění tento soubor spustit, skript nahlásí chybu a zastaví se.
-nt pro porovnání dat souborů
Operátor -nt bere dva operandy a testuje, zda je první soubor novější než druhý. Není součástí formální specifikace POSIX, takže spoléhání na -nt povede k mírně méně přenosným skriptům. Funguje však jak v Bash, tak v Zsh, a pokud píšete skript jen pro vlastní potřebu, není problém ho zaměřit na konkrétní shell.
[[ $file1 -nt $file2 ]]
Jedním z dobrých použití -nt je zjistit nejnovější soubor v sadě:
unset -v latest
for file in *; do
[[ $file -nt $latest ]] && latest=$file
done
echo $latest
Můžete udělat něco podobného pomocí ls/find v pipeline, ale výše uvedený přístup má méně závislostí a může být přehlednější. Měl by být také odolnější, protože parsování výstupu ls není zcela spolehlivé.
Tento operátor můžete také použít k přiblížení základní formy Make:
[[ "main.c" -nt "main" ]] && gcc -o main main.c
Stejně jako Make tento příkaz zkompiluje zdrojový kód v C pouze tehdy, pokud se změnil od doby, kdy byl vytvořen binární soubor. Pro počáteční případ, kdy program nikdy nebyl kompilován, ho můžete kombinovat s operátorem -f:
[[ ! -f "main" || "main.c" -nt "main" ]] && gcc -o main main.c