Avec bash, définissez les paramètres glob afin que les correspondances manquantes ne déclenchent pas d'erreur :
shopt -u failglob # avoid failure report (and discarding the whole line).
shopt -s nullglob # remove (erase) non-matching globs.
ls ?c c?
Le point d'interrogation est un caractère global représentant un seul caractère. Puisque vous voulez des noms de fichiers à deux caractères, l'un d'eux doit être un c
, et donc c'est soit le premier caractère, soit le dernier caractère.
Avec shopt -s dotglob
cela afficherait également un fichier nommé .c
.
S'il n'y a pas de fichiers correspondants, la définition de ces options du shell entraîne la suppression de tous les arguments, ce qui se traduit par un simple ls
-- listant n'importe quoi/tout par défaut.
Utilisez ceci à la place :
shopt -s nullglob ## drop any missing globs
set -- ?c c? ## populate the [email protected] array with (any) matches
if [ $# -gt 0 ] ## if there are some, list them
ls -d "[email protected]"
fi
Je pense que la meilleure façon est d'utiliser find
:
find . -type f -name '*c*' -name '??'
Cela effectuera une recherche récursive. Pour lister uniquement les fichiers du répertoire courant :
find . ! -name . -prune -type f -name '*c*' -name '??'
Si les fichiers existent (et n'ont pas de caractères d'échappement comme \c
), vous pouvez utiliser un glob :
echo ?c c?
qui correspondra aux fichiers qui ont un caractère (?
) suivi d'un c
ou qui ont un c
suivi d'un caractère (?
).
Mais échouera avec les noms de fichiers qui commencent par un tiret comme -n
ou -e
ou avec des barres obliques inverses comme \c
ou \n
avec echo
comme -e
et -n
sont spéciaux pour (certains shells) echo
et \c
ou \n
serait interprété comme une séquence d'échappement (\c
termine la sortie et \n
imprime une nouvelle ligne, pas les caractères textuels \n
dans certaines implémentations shell de echo et avec bash lorsque l'option shopt -s xpg_echo
est réglé). D'autres applications ou utilitaires (comme ls
) aura d'autres options et peut échouer avec de nombreux autres caractères commençant par un tiret ou interpréter d'autres caractères d'échappement dans les noms de fichiers.
Listera également un fichier nommé cc
deux fois.
-
Si un fichier peut commencer par un tiret (comme -n), utilisez :
$ ls -d -- ?n -n
Ou mieux :
$ ls -d ./?n ./-n
Mises en garde
-
Glob ne correspond à aucun fichier.
-
Si les fichiers n'existent pas, le glob ne sera pas développé et le glob sera imprimé dans sa forme d'origine.
$ echo ?m m? ?m m?
-
Sauf en zsh.
$ zsh -c 'echo ?m m?' zsh:1: no matches found: ./m?
Le shell se terminera avec une erreur.
Ce comportement est contrôlé par lenomatch
de Zsh option.$ zsh -c 'setopt +o nomatch; echo ?m m?' ?m m?
Ou :
$ zsh -c 'echo ?m(N) m?(N)' ?m m?
Mais cela imprimera
mm
deux fois. -
Dans bash, vous pourriez obtenir un résultat similaire à zsh si l'option shell
failglob
est défini :$ bash -c 'shopt -s failglob; echo ?m m?' bash: no match: ?m
Mais le script ne s'arrêtera pas, le shell ne se fermera pas. Eh bien, techniquement, la ligne où le glob est utilisé n'est pas exécutée davantage mais l'exécution reprend à la ligne de script suivante.
-
En bash, vous pouvez définir l'option
nullglob
pour supprimer les globs qui ne correspondent pas :$ bash -c 'shopt -s nullglob; echo ?m m? done' done
-
-
Utilisation de ls (similaire à d'autres programmes)
-
Avec les fichiers correspondants, il n'y aura pas de problème, mais les répertoires seront également mis en correspondance (et répertoriés) :
$ ls ?c c? bc cz sc ac: hjk
Mieux vaut utiliser
-d
avecls
(les répertoires seront inclus mais pas développés).$ ls -d ?c c? ac bc cz sc
-
Les globs ne correspondent pas à un fichier (ou un répertoire)
Alors
ls
signalera un échec$ ls ?m m? ls: cannot access '?m': No such file or directory
D'autres programmes pourraient (probablement) ne pas faire des vérifications similaires.
-
Utilisation de
nullglob
avec bash donnera une liste vide à ls, donc, il listera le contenu ou le pwd comme si seulementls
a été exécuté :$ ls ?m m? ac a.out cz 3 b sc ab bc
Cela pourrait être évité en utilisant
./
$ ls -d ./?m ./m? ls: cannot access './?m': No such file or directory ls: cannot access './m?': No such file or directory
-
Ou vous pouvez utiliser une regex de recherche (mais elle traversera les sous-répertoires avec prune
manquant) (Notez que cela ne répétera pas un fichier appelé cc) :
$ find . ! -name . -prune -regex '.*/\(.c\|c.\)'
./ac
./cc
./sc
./bc
./cz