Snažím se napsat if
příkaz k testování, zda existují nějaké soubory odpovídající určitému vzoru. Pokud je v adresáři textový soubor, měl by spustit daný skript.
Můj kód aktuálně:
if [ -f /*.txt ]; then ./script fi
Uveďte prosím nějaké nápady; Skript chci spustit pouze v případě, že existuje .txt
v adresáři.
Přijatá odpověď:
[ -f /*.txt ]
vrátí true, pouze pokud existuje jeden (a pouze jeden) neskrytý soubor v /
jehož jméno končí na .txt
a pokud je tento soubor běžným souborem nebo symbolickým odkazem na běžný soubor.
Je to proto, že zástupné znaky jsou před předáním příkazu rozbaleny shellem (zde [
).
Pokud tedy existuje /a.txt
a /b.txt
, [
bude předáno 5 argumentů:[
, -f
, /a.txt
, /b.txt
a ]
. [
by si pak stěžoval, že -f
je uvedeno příliš mnoho argumentů.
Pokud chcete zkontrolovat, že *.txt
vzor se rozšíří na alespoň jeden neskrytý soubor (běžný nebo ne) v bash
shell:
shopt -s nullglob
set -- *.txt
if [ "$#" -gt 0 ]; then
./script "[email protected]" # call script with that list of files.
fi
# Or with bash arrays so you can keep the arguments:
files=( *.txt )
# apply C-style boolean on member count
(( ${#files[@]} )) && ./script "${files[@]}"
shopt -s nullglob
je bash
konkrétní (shopt
je nullglob
ve skutečnosti pochází z zsh
), ale shelly jako ksh93
, zsh
, yash
, tcsh
mít ekvivalentní prohlášení.
Pomocí zsh
, test na existují soubory odpovídající vzoru lze zapsat pomocí anonymní funkce a N
(pro nullglob
) a Y1
(pro zastavení po prvním nalezení) kvalifikátor glob:
if ()(($#)) *.txt(NY1); then
do-something
fi
Všimněte si, že tito najdou tyto soubory čtením obsahu adresáře, vůbec se nepokouší o přístup k těmto souborům, což je efektivnější než řešení, která volají příkazy jako ls
nebo stat
na tomto seznamu souborů vypočítaných shellem.
Standardní sh
ekvivalent by byl:
set -- [*].txt *.txt
case "$1$2" in
('[*].txt*.txt') ;;
(*) shift; script "[email protected]"
esac
Problém je v tom, že u shellů Bourne nebo POSIX, pokud vzor neodpovídá, roztáhne se sám na sebe. Pokud tedy *.txt
se rozšíří na *.txt
, nevíte, zda je to tím, že neexistuje žádný .txt
soubor v adresáři nebo protože existuje jeden soubor s názvem *.txt
. Pomocí [*].txt *.txt
umožňuje rozlišovat mezi těmito dvěma.
Nyní, pokud chcete zkontrolovat, že *.txt
odpovídá alespoň jednomu běžnému soubor nebo symbolický odkaz na běžný soubor (jako váš [ -f *.txt ]
navrhuje, že chcete udělat), nebo že všechny soubory, které odpovídají *.txt
jsou pravidelné soubory (po rozlišení symbolických odkazů), to je další věc.
Pomocí zsh
:
if ()(($#)) *.txt(NY1-.); then
echo "there is at least one regular .txt file"
fi
if ()(($#)) *.txt(NY1^-.); then
echo "there is at least one non-regular .txt files"
fi
(odstraňte -
pokud chcete provést test před rozlišením symbolických odkazů, považujte symbolické odkazy za nestandardní soubory, ať už odkazují na běžné soubory nebo ne).