J'essaie d'écrire une if
déclaration pour tester s'il existe des fichiers correspondant à un certain modèle. S'il y a un fichier texte dans un répertoire, il doit exécuter un script donné.
Mon code actuellement:
if [ -f /*.txt ]; then ./script fi
Veuillez donner quelques idées; Je veux seulement exécuter le script s'il y en a un .txt
dans le répertoire.
shell-script
files
wildcards
test
user40952
la source
la source
/
? De plus, il vous manque un point-virgule avantfi
.find
comme expliqué ici sur stackoverflow .Réponses:
renvoie true uniquement s'il existe un (et un seul) fichier non masqué
/
dont le nom se termine.txt
et si ce fichier est un fichier normal ou un lien symbolique vers un fichier normal.En effet, les caractères génériques sont développés par le shell avant d'être transmis à la commande (ici
[
).Donc , s'il y a un
/a.txt
et/b.txt
,[
sera transmis 5 arguments:[
,-f
,/a.txt
,/b.txt
et]
.[
se plaindrait alors qu'on-f
lui donne trop d'arguments.Si vous souhaitez vérifier que le
*.txt
modèle se développe en au moins un fichier non caché (normal ou non):shopt -s nullglob
estbash
spécifique, mais des coquilles commeksh93
,zsh
,yash
,tcsh
ont des déclarations équivalentes.Notez qu'il trouve ces fichiers en lisant le contenu du répertoire, il n'essaie pas du tout d'accéder à ces fichiers, ce qui le rend plus efficace que les solutions qui appellent des commandes comme
ls
oustat
sur cette liste de fichiers calculée par le shell.L'
sh
équivalent standard serait:Le problème est qu'avec les shells Bourne ou POSIX, si un modèle ne correspond pas, il se développe lui-même. Donc, si se
*.txt
développe en*.txt
, vous ne savez pas si c'est parce qu'il n'y a pas de.txt
fichier dans le répertoire ou parce qu'il y a un fichier appelé*.txt
. L'utilisation[*].txt *.txt
permet de distinguer les deux.la source
[ -f /*.txt ]
est assez rapide par rapport àcompgen
.[ -f /*.txt ]
aurait tort, mais dans mon test sur un répertoire qui contient des3425
fichiers,94
dont des fichiers txt non cachés,compgen -G "*.txt" > /dev/null 2>&1
semble être aussi rapide queset -- *.txt; [ "$#" -gt 0 ]
(20,5 secondes pour les deux lorsqu'il est répété 10000 fois dans mon cas).Vous pouvez toujours utiliser
find
:Explication:
find .
: recherche dans le répertoire courant-maxdepth 1
: ne recherche pas les sous-répertoires-type f
: recherche uniquement les fichiers standardname "*.txt"
: rechercher les fichiers se terminant par.txt
2>/dev/null
: rediriger les messages d'erreur vers/dev/null
| grep -q .
: grep pour n'importe quel caractère, retournera false si aucun caractère n'a été trouvé.&& ./script
: Exécuter./script
uniquement si la commande précédente a réussi (&&
)la source
find
ne renvoie false que s'il a du mal à rechercher des fichiers, pas s'il ne trouve aucun fichier. Vous voulez diriger la sortiegrep -q .
pour vérifier si elle trouve quelque chose.chmod a-x .
.Une solution possible est également intégrée à Bash
compgen
. Cette commande renvoie toutes les correspondances possibles pour un modèle de globalisation et possède un code de sortie indiquant si des fichiers correspondent.J'ai trouvé cette question en cherchant des solutions plus rapides.
la source
LC_ALL=C compgen -G "*.txt" > /dev/null
.Voici une doublure pour le faire:
les fichiers existent
les fichiers n'existent pas
Cette approche utilise les opérateurs
||
et&&
dans bash. Ce sont les opérateurs "ou" et "et".Donc, si la commande stat renvoie un
$?
égal à 0, le premierecho
est appelé, s'il renvoie un 1, le secondecho
est appelé.renvoyer les résultats de stat
Cette question est largement couverte sur stackoverflow:
la source
stat
quandls -d
peut faire la même chose?ls -d
répertorie un répertoire? Cela ne semblait pas fonctionner lorsque j'ai essayé de lister un répertoire avec des fichiersls -d *.pl
par exemple.&&
parls *.txt
et il fonctionnera aussi bien. Assurez-vous d'envoyer la stdout et la stderr/dev/null
comme suggéré par @slm.ls *.txt
et il n'y a pas de fichiers présents dans le répertoire cela renvoie une$? = 2
, qui continuera de fonctionner avec le cas alors, mais ce fut l' une de mes raisons de choisirstat
plusls
. Je voulais un 0 pour le succès et un 1 pour un échec.ls -d
est de lister les répertoires au lieu de leur contenu. Il en va dels -d
mêmelstat
pour le fichier, tout comme GNUstat
. Les commandes d'état de sortie non nul qui retournent en cas d'échec sont spécifiques au système, il est peu logique de faire des hypothèses à leur sujet.Comme le souligne Chazelas, votre script échouerait si l'expansion générique correspond à plusieurs fichiers.
Cependant, il y a une astuce que j'utilise ( même si je ne l'aime pas beaucoup ) pour se déplacer:
Comment ça marche?
L'expansion des caractères génériques correspondra à un tableau de noms de fichiers, nous obtenons le premier s'il y en a, sinon null si aucune correspondance.
la source
.txt
fichiers de type régulier . Essayez par exemple aprèsmkdir a.txt; mkfifo b.txt; echo regular > c.txt
.Aussi simple que:
wc -l
compte les lignes du caractère générique étendu.la source
ls
sortie et ne l'examinez presque jamais$?
directement, car elle le faitif
déjà. En outre, utiliserwc
pour voir si quelque chose s'est produit est également mal dirigé.J'aime la solution de tableau précédente, mais cela pourrait devenir un gaspillage avec un grand nombre de fichiers - le shell utiliserait beaucoup de mémoire pour construire le tableau, et seul le premier élément serait testé.
Voici une structure alternative que j'ai testée hier:
$ cd /etc; if [[ $(echo * | grep passwd) ]];then echo yes;else echo no;fi yes $ cd /etc; if [[ $(echo * | grep password) ]];then echo yes;else echo no;fi no
La valeur de sortie du grep semble déterminer le chemin à travers la structure de contrôle. Cela teste également avec des expressions régulières plutôt qu'avec des modèles de shell. Certains de mes systèmes ont la commande "pcregrep" qui permet des correspondances regex beaucoup plus sophistiquées.
(J'ai modifié cette réponse pour supprimer un "ls" dans la substitution de commande après avoir lu la critique ci-dessus pour l'avoir analysée.)
la source
si vous souhaitez utiliser une clause if, évaluez le nombre:
la source