Je sais utiliser la commande ls
listera tous les répertoires. Mais qu'est-ce que le ls *
commande faire ? Je l'ai utilisé et il répertorie simplement les répertoires. Est-ce que l'étoile devant ls
signifie à quelle profondeur il listera les répertoires ?
Réponse acceptée :
ls
répertorie les fichiers et le contenu des répertoires qui lui sont transmis en tant qu'arguments, et si aucun argument n'est donné, il répertorie le répertoire courant. On peut également lui passer un certain nombre d'options qui affectent son comportement (voir man ls
pour plus de détails).
Si ls
reçoit un argument appelé *
, il recherchera un fichier ou un répertoire appelé *
dans le répertoire courant et listez-le comme n'importe quel autre. ls
ne traite pas le *
caractère d'une autre manière que toute autre.
Cependant si ls *
est un shell ligne de commande, c'est-à-dire code dans le langage d'un shell Unix , alors le shell développera ce *
selon son globbing (également appelé Génération de noms de fichiers ou Développement du nom de fichier/chemin d'accès ) règles.
Bien que différents shells prennent en charge différents opérateurs de globalisation, la plupart d'entre eux s'accordent sur le plus simple *
. *
comme un motif signifie n'importe quel nombre de caractères, donc *
en tant que glob
développera la liste des fichiers dans les répertoires actuels qui correspondent à ce modèle. Il y a une exception cependant qu'un point de tête (.
) dans un nom de fichier doit correspondre explicitement, donc *
s'étend en fait à la liste des fichiers et répertoires ne commençant pas par .
(par ordre lexical).
Par exemple, si le répertoire courant contient les fichiers appelés .
, ..
, .foo
, -l
et foo bar
, *
sera étendu par le shell à deux arguments à passer à ls
:-l
et foo bar
, ce sera donc comme si vous aviez tapé :
ls -l "foo bar"
ou
'ls' "-l" foo bar
Ce sont trois façons d'exécuter exactement la même commande. Dans les 3 cas, le ls
commande (qui sera probablement exécutée depuis /bin/ls
à partir d'une recherche de répertoires mentionnés dans $PATH
) recevront ces 3 arguments :"ls", "-l" et "foo bar".
Incidemment, dans ce cas, ls
traitera le premier (à proprement parler second ) un en option.
Maintenant, comme je l'ai dit, différents shells ont différents opérateurs de globalisation. Il y a quelques décennies, zsh
introduit le **/
opérateur¹ qui signifie correspondre à n'importe quel niveau de sous-répertoires, abréviation de (*/)#
et ***/
qui est identique sauf qu'il suit les liens symboliques tout en descendant les répertoires.
Il y a quelques années (juillet 2003, ksh93o+
), ksh93
a décidé de copier ce comportement mais a décidé de le rendre facultatif et ne couvrait que le **
cas (pas ***
). Aussi, tandis que **
seul n'était pas spécial dans zsh
² (signifiait simplement la même chose que *
comme dans les autres shells traditionnels depuis **
signifie n'importe quel nombre de caractères suivi de n'importe quel nombre de caractères), dans ksh93, **
signifiait la même chose que **/*
(donc tout fichier ou répertoire en dessous de l'actuel (hors fichiers cachés)³.
bash
copié ksh93
quelques années plus tard (février 2009, bash 4.0), avec la même syntaxe mais une différence fâcheuse :le **
de bash était comme zsh
c'est ***
, c'est-à-dire qu'il suivait des liens symboliques lors de la récurrence dans des sous-répertoires, ce qui n'est généralement pas ce que vous voulez qu'il fasse et peut avoir des effets secondaires désagréables. Il a été partiellement corrigé dans bash-4.3 en ce sens que les liens symboliques étaient toujours suivis, mais la récursivité s'est arrêtée là. Il a été entièrement corrigé dans la version 5.0.
yash
ajouté **
dans la version 2.0 en 2008, activé avec le extended-glob
option. Son implémentation est plus proche de zsh
est dans ce **
seul n'est pas spécial. Dans la version 2.15 (2009), il a ajouté ***
comme dans zsh
et deux de ses propres extensions :.**
et .***
pour inclure les répertoires cachés lors de la récurrence (en zsh
, le D
qualificatif global (comme dans **/*(D)
) prendra en compte les fichiers et répertoires cachés, mais si vous souhaitez uniquement parcourir les répertoires cachés sans développer les fichiers cachés, vous avez besoin de ((*|.*)/)#*
ou **/[^.]*(D)
).
La coquille de poisson prend également en charge **
. Comme la version précédente de bash
, il suit les liens symboliques lors de la descente de l'arborescence des répertoires. Dans ce shell cependant **/*
n'est pas identique à **
. **
est plus une extension de *
qui peut s'étendre sur plusieurs répertoires. En fish
, **/*.c
correspondra à a/b/c.c
mais pas a.c
, tandis que a**.c
correspondra à a.c
et ab/c/d.c
et zsh
c'est **/.*
par exemple doit être écrit .* **/.*
. Là, ***
est compris comme **
suivi de *
donc identique à **
.
tcsh
également ajouté un globstar
option dans V6.17.01 (mai 2010) et prend en charge à la fois **
et ***
à la zsh
.
Donc en tcsh
, bash
et ksh93
, (lorsque l'option correspondante est activée (globstar
)) ou fish
, **
développe tous les fichiers et répertoires sous l'actuel, et ***
est identique à **
pour fish
, un lien symbolique traversant **
pour tcsh
avec globstar
, et identique à *
dans bash
et ksh93
(bien qu'il ne soit pas impossible que les futures versions de ces shells traversent également des liens symboliques).
Ci-dessus, vous aurez remarqué la nécessité de s'assurer qu'aucune des extensions n'est interprétée comme une option. Pour cela, vous feriez :
ls -- *
Ou :
ls ./*
Il y a quelques commandes (peu importe pour ls
) où la seconde est préférable puisque même avec le --
certains noms de fichiers peuvent être traités spécialement. C'est le cas de -
pour la plupart des utilitaires de texte, cd
et pushd
et les noms de fichiers contenant le =
caractère pour awk
par exemple. Préfixe ./
à tous les arguments enlève leur signification particulière (au moins pour les cas mentionnés ci-dessus).
Il convient également de noter que la plupart des shells ont un certain nombre d'options qui affectent le comportement global (comme si les fichiers de points sont ignorés ou non, l'ordre de tri, que faire s'il n'y a pas de correspondance…), voir aussi le $FIGNORE
paramètre dans ksh
Aussi, dans chaque shell sauf csh
, tcsh
, fish
et zsh
, si le motif global ne correspond à aucun fichier, le modèle est passé en tant qu'argument non développé, ce qui provoque une confusion et éventuellement des bogues. Par exemple, s'il n'y a pas de fichier non caché dans le répertoire courant
ls *
Appelera en fait ls
avec les deux arguments ls
et *
. Et comme il n'y a pas de fichier du tout, donc aucun ne s'appelle *
soit, vous verrez un message d'erreur de ls (pas le shell) comme :ls: cannot access *: No such file or directory
, qui est connu pour faire croire aux gens qu'il s'agissait de ls
qui étendait en fait les globs.
Le problème est encore pire dans des cas comme :
rm -- *.[ab]
S'il n'y a pas de *.a
ni *.b
fichier dans le répertoire courant, vous risquez de finir par supprimer un fichier appelé *.[ab]
par erreur (csh
, tcsh
, et zsh
signalerait une pas de correspondance erreur et n'appellerait pas rm
(et fish
ne prend pas en charge le [...]
caractères génériques)).
Si vous voulez passer un *
littéral à ls
, vous devez citer ce *
caractère d'une certaine manière comme dans ls *
ou ls '*'
ou ls "*"
. Dans les shells de type POSIX, le globbing peut être complètement désactivé en utilisant set -o noglob
ou set -f
(ce dernier ne fonctionne pas dans zsh
sauf en sh
/ksh
émulation).
.