Sto cercando di scrivere un if
istruzione per verificare se ci sono file che corrispondono a un determinato modello. Se c'è un file di testo in una directory, dovrebbe eseguire un determinato script.
Il mio codice attualmente:
if [ -f /*.txt ]; then ./script fi
Si prega di fornire alcune idee; Voglio eseguire lo script solo se è presente un .txt
nella directory.
Risposta accettata:
[ -f /*.txt ]
ritornerebbe vero solo se ce n'è uno (e solo uno) file non nascosto in /
il cui nome termina con .txt
e se quel file è un file normale o un collegamento simbolico a un file normale.
Questo perché i caratteri jolly vengono espansi dalla shell prima di essere passati al comando (qui [
).
Quindi, se c'è un /a.txt
e /b.txt
, [
verranno passati 5 argomenti:[
, -f
, /a.txt
, /b.txt
e ]
. [
si lamenterebbe quindi che -f
riceve troppi argomenti.
Se vuoi controllare che il *.txt
pattern si espande in almeno un file non nascosto (normale o meno), nel bash
guscio:
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
è bash
specifico (shopt
è, nullglob
in realtà viene da zsh
), ma shell come ksh93
, zsh
, yash
, tcsh
avere dichiarazioni equivalenti.
Con zsh
, il test per ci sono file che corrispondono a un modello può essere scritto utilizzando una funzione anonima e il N
(per nullglob
) e Y1
(per fermarsi dopo la prima ricerca) qualificatore glob:
if ()(($#)) *.txt(NY1); then
do-something
fi
Nota che quelli trovano quei file leggendo il contenuto della directory, non tenta affatto di accedere a quei file, il che lo rende più efficiente delle soluzioni che chiamano comandi come ls
o stat
su quell'elenco di file calcolato dalla shell.
Lo standard sh
l'equivalente sarebbe:
set -- [*].txt *.txt
case "$1$2" in
('[*].txt*.txt') ;;
(*) shift; script "[email protected]"
esac
Il problema è che con le shell Bourne o POSIX, se un pattern non corrisponde, si espande su se stesso. Quindi se *.txt
si espande in *.txt
, non sai se è perché non c'è .txt
file nella directory o perché esiste un file chiamato *.txt
. Utilizzando [*].txt *.txt
permette di discriminare tra i due.
Ora, se vuoi controllare che il *.txt
corrisponde ad almeno un normale file o collegamento simbolico a un file normale (come il tuo [ -f *.txt ]
suggerisce di volerlo fare), o che tutti i file che corrispondono a *.txt
sono normali file (dopo la risoluzione del collegamento simbolico), questa è un'altra questione.
Con 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
(rimuovere il -
se vuoi fare il test prima della risoluzione del collegamento simbolico, considera i collegamenti simbolici come file non regolari indipendentemente dal fatto che puntino a file normali o meno).