Je sais que l'utilisation de 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. L'étoile devant ls
signifie-t-elle la profondeur de la liste des répertoires?
ls
répertorie les fichiers et le contenu des répertoires auxquels il est transmis en tant qu'arguments, et si aucun argument n'est donné, il répertorie le répertoire actuel. Il peut également être transmis 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 le listera comme n'importe quel autre. ls
ne traite pas le caractère *
Autrement que par tout autre.
Cependant, si ls *
Est une ligne de commande Shell, le Shell étendra ce *
En fonction du globbing du Shell correspondant = (également appelé règles Génération de nom de fichier ou Expansion de nom de fichier ).
Alors que différents shells prennent en charge différents opérateurs de globbing, la plupart d'entre eux s'accordent sur le plus simple *
. *
En tant que modèle signifie n'importe quel nombre de caractères, donc *
En tant que glob
s'étendra à la liste des fichiers dans les répertoires actuels qui correspondent à ce modèle. Il existe cependant une exception: le caractère point (.
) Dans un nom de fichier doit être mis en correspondance explicitement, donc *
Se développe en fait à la liste des fichiers et répertoires ne commençant pas par .
(par ordre lexicographique).
Par exemple, si le répertoire actuel contient les fichiers appelés .
, ..
, .foo
, -l
Et foo bar
, *
sera étendu par le Shell à deux arguments pour passer à ls
: -l
et foo bar
, donc ce sera 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, la commande ls
(qui sera probablement exécutée à partir de /bin/ls
À partir d'une recherche de répertoires mentionnés dans $PATH
) Passera ces 3 arguments: "ls" , "-l" et "foo bar".
Par ailleurs, dans ce cas, ls
traitera la première (à proprement parler second ) comme option.
Maintenant, comme je l'ai dit, différents shells ont différents opérateurs de globbing. Il y a quelques décennies, zsh
a introduit l'opérateur **/
¹ qui signifie correspondre à n'importe quel niveau de sous-répertoires, abréviation de (*/)#
Et ***/
Qui est le même sauf que 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 ***
). De plus, alors que **
Seul n'était pas spécial dans zsh
² (signifiait simplement la même chose que *
Comme dans d'autres coquilles traditionnelles puisque **
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 sous le courant (à l'exception des fichiers cachés).
bash
a copié ksh93
Quelques années plus tard (février 2009, bash 4.0), avec la même syntaxe mais une différence malheureuse: **
De bash était comme zsh
' s ***
, c'est-à-dire qu'il suivait des liens symboliques lors de la récursivité 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 5.0.
yash
a ajouté **
Dans la version 2.0 en 2008, activé avec l'option extended-glob
. Son implémentation est plus proche de celle de zsh
dans la mesure où **
À lui 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 des répertoires cachés lors de la récursivité ( dans zsh
, le D
glob qualifier (comme dans **/*(D)
) considérera les fichiers et répertoires cachés, mais si vous vous voulez seulement parcourir les répertoires cachés mais pas développer les fichiers cachés, vous avez besoin de ((*|.*)/)#*
ou **/[^.]*(D)
).
Shell 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 de répertoires. Dans ce shell, cependant, **/*
N'est pas identique à **
. **
Est plus une extension de *
Qui peut s'étendre sur plusieurs répertoires. Dans 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
, par exemple, **/.*
Doivent être écrits .* **/.*
. Là, ***
Est compris comme **
Suivi de *
Donc comme **
.
tcsh
a également ajouté une option globstar
dans la version V6.17.01 (mai 2010) et prend en charge **
Et ***
À la zsh
.
Ainsi, dans tcsh
, bash
et ksh93
, (Lorsque l'option correspondante est activée (globstar
)) ou fish
, **
Développe tous les fichiers et répertoires en dessous de l'actuel, et ***
Est identique à **
Pour fish
, un lien symbolique traversant **
Pour tcsh
avec globstar
, et la même chose que *
Dans bash
et ksh93
(Bien qu'il ne soit pas impossible que les futures versions de ces shells soient également traverser les liens symboliques).
Ci-dessus, vous aurez remarqué la nécessité de vous assurer qu'aucune des extensions n'est interprétée comme une option. Pour cela, vous feriez:
ls -- *
Ou:
ls ./*
Il y a certaines commandes (cela n'a pas d'importance pour ls
) où la seconde est préférable car 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 qui contiennent le caractère =
Pour awk
par exemple. Ajouter ./
À tous les arguments supprime 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 de globbing (comme si les fichiers dot 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
De plus, dans chaque shell, mais csh
, tcsh
, fish
et zsh
, si le globbing pattern ne correspond à aucun fichier, le modèle est transmis sous forme d'argument non développé, ce qui provoque de la confusion et éventuellement des bogues. Par exemple, s'il n'y a pas de fichier non caché dans le répertoire courant
ls *
Appellera 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 *
Non plus, 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 que c'est ls
qui a réellement étendu les globes.
Le problème est encore pire dans des cas comme:
rm -- *.[ab]
S'il n'y a pas de fichier *.a
Ni *.b
Dans le répertoire en cours, vous risquez de supprimer un fichier appelé *.[ab]
Par erreur (csh
, tcsh
et zsh
signaleraient une erreur no match et n'appelleraient pas rm
(et fish
ne fait pas ') t prend en charge les caractères génériques [...]
)).
Si vous voulez passer un littéral *
À ls
, vous devez citer ce caractère *
D'une manière ou d'une autre comme dans ls \*
Ou ls '*'
ou ls "*"
. Dans les shells de type POSIX, la globalisation peut être complètement désactivée en utilisant set -o noglob
Ou set -f
(Ce dernier ne fonctionne pas dans zsh
sauf dans sh
/ksh
émulation).
¹ Bien que (*/)#
Ait toujours été pris en charge, il a d'abord été raccourci en tant que ..../
En zsh-2.0 (et éventuellement avant), puis ****/
En 2.1 avant d'obtenir sa forme définitive **/
En 2.2 (début 1992)
² L'option globstarshort
, a depuis été ajoutée (en 2015) pour permettre d'utiliser **
Et ***
Au lieu de **/*
et ***/*
respectivement
La commande ls
par défaut est ls .
: Liste toutes les entrées du répertoire actuel.
La commande ls *
signifie 'exécuter ls sur l'extension de *
Modèle de coque '
Le *
le modèle est traité par le shell et s'étend à toutes les entrées du répertoire en cours, à l'exception de celles commençant par .
. Cela ira d'un niveau en profondeur.
L'interprétation du double ou du triple *
les modèles dépendent du shell réellement utilisé.
*
est un caractère générique qui correspond à 0 ou plusieurs caractères. Certains obus modernes récurseront dans des sous-répertoires en voyant le **
modèle.
Vous pouvez démystifier l'ensemble du processus en tapant echo
au lieu de ls
d'abord, pour voir à quoi la commande se développe:
$ echo *
Applications Downloads Documents tmp.html
Donc dans ce cas, ls *
se développe en ls Applications Downloads Documents tmp.html
$ echo **
Applications Downloads Documents tmp.html
$ echo ***
Applications Downloads Documents tmp.html
Donc pas de changement. Cela suppose que vous utilisez bash
comme shell - la plupart des gens le sont, et différents shells ont un comportement différent. Si vous utilisez ash
ou csh
ou ksh
ou zsh
, vous pouvez vous attendre à ce que les choses fonctionnent différemment. C'est le point d'avoir différents obus.
Essayons donc quelque chose de différent (toujours avec bash
) pour avoir une idée du globbing (*
) l'opérateur peut faire pour nous. Par exemple, nous pouvons filtrer par partie du nom:
$ echo D*
Downloads Documents
Et fait intéressant, une barre oblique de fin fait implicitement partie de tout nom de répertoire. Donc */
ne produira que les répertoires (et les liens symboliques vers les répertoires):
$ echo */
Applications/ Downloads/ Documents/
Et nous pouvons filtrer à plusieurs niveaux en plaçant des barres obliques au milieu:
$ echo D*/*/
Documents/Work/ /Documents/unfinished/
Étant donné que le répertoire Downloads
ne contient aucun sous-répertoire, il ne se retrouve pas dans la sortie. Ceci est très utile pour examiner uniquement les fichiers que vous souhaitez. J'utilise des commandes comme celle-ci tout le temps:
$ ls -l /home/*/public_html/wp-config.php
S'il en existe, tous les wp-config.php
fichiers qui existent au niveau de base de tout utilisateur public_html
répertoire. Ou peut-être pour être plus complet:
$ find /home/*/public_html/ -name wp-config.php
Cela trouvera tout wp-config.php
fichiers dans n'importe quel utilisateur public_html
répertoires ou l'un de leurs sous-répertoires, mais il fonctionnera plus efficacement que simplement find /home/ -name wp-config.php
car il n'examinera rien mais le public_html
répertoires pour chacun des utilisateurs.
Dans certains shells, y compris bash 4.x avec l'option globstar
activée, **
effectuera un glob récursif, des répertoires correspondants décroissants. Des astérisques supplémentaires ne modifient pas davantage cette opération.
Si vous voulez "plonger profondément", utilisez l'option ls -R (récursive), ou utilisez find, comme ceci:
find . -ls
"find" plongera au bas de l'arborescence des répertoires (comme le sera 'ls -R'), et a beaucoup plus d'options, comme lister les répertoires (-type d), les fichiers uniquement (-type f) ou afficher les fichiers ayant d'autres caractéristiques (aucun utilisateur dans/etc/passwd, autorisations spécifiques, et bien plus encore). "find" est également un peu plus sûr dans les scripts (en raison de règles de globalisation incohérentes entre les shells, ainsi que des échappements spéciaux pour les fichiers contenant des tirets, etc.).
Le remplacement des caractères génériques du shell ne fonctionnera pas avec un simple astérisque '*' sur les fichiers dot. Pour répertorier uniquement les fichiers dot, utilisez:
ls .??*