Quelle est la différence entre du -sh *
et du -sh ./*
?
Remarque :Ce qui m'intéresse, c'est le *
et ./*
pièces.
Réponse acceptée :
$ touch ./-c $'an12tb' foo $ du -hs * 0 a 12 b 0 foo 0 total
Comme vous pouvez le voir, le -c
le fichier a été pris en option pour du
et n'est pas signalé (et vous voyez le total
ligne à cause de du -c
). Aussi, le fichier nommé an12tb
nous fait penser qu'il existe des fichiers appelés a
et b
.
$ du -hs -- *
0 a
12 b
0 -c
0 foo
C'est mieux. Au moins cette fois -c
n'est pas considéré comme une option.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
C'est même mieux. Le ./
le préfixe empêche -c
d'être pris en option et l'absence de ./
avant b
dans la sortie indique qu'il n'y a pas de b
fichier là-dedans, mais il y a un fichier avec un caractère de nouvelle ligne (mais voir ci-dessous pour d'autres digressions à ce sujet).
Il est recommandé d'utiliser le ./
préfixe si possible, et sinon et pour des données arbitraires, vous devriez toujours utiliser :
cmd -- "$var"
ou :
cmd -- $patterns
Si cmd
ne prend pas en charge --
pour marquer la fin des options, il faut le signaler comme bogue à son auteur (sauf quand c'est par choix et documenté comme pour echo
).
Il y a des cas où ./*
résout les problèmes qui --
n'a pas. Par exemple :
awk -f file.awk -- *
échoue s'il existe un fichier nommé a=b.txt
dans le répertoire courant (définit la variable awk a
vers b.txt
au lieu de lui dire de traiter le fichier).
awk -f file.awk ./*
N'a pas le problème car ./a
n'est pas un nom de variable awk valide, donc ./a=b.txt
n'est pas considéré comme une affectation de variable.
cat -- * | wc -l
échoue s'il existe un fichier appelé -
dans le répertoire courant, comme cela indique cat
lire depuis son stdin (-
est spécial pour la plupart des utilitaires de traitement de texte et pour cd
/pushd
).
cat ./* | wc -l
est OK car ./-
n'est pas spécial pour cat
.
Des choses comme :
grep -l -- foo *.txt | wc -l
pour compter le nombre de fichiers contenant foo
sont erronés car ils supposent que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne (wc -l
compte les caractères de saut de ligne, ceux générés par grep
pour chaque fichier et ceux dans les noms de fichiers eux-mêmes). Vous devriez utiliser à la place :
grep -l foo ./*.txt | grep -c /
(en comptant le nombre de /
caractères est plus fiable car il ne peut y en avoir qu'un par nom de fichier).
Pour grep
récursif , l'astuce équivalente consiste à utiliser :
grep -rl foo .//. | grep -c //
./*
peut cependant avoir des effets secondaires indésirables.
cat ./*
ajoute deux caractères supplémentaires par fichier, ce qui vous ferait atteindre plus tôt la limite de la taille maximale des arguments + environnement. Et parfois, vous ne voulez pas que ./
à signaler dans la sortie. Comme :
grep foo ./*
Renvoie :
./a.txt: foobar
au lieu de :
a.txt: foobar
Digressions supplémentaires
. J'ai l'impression que je dois développer cela ici, suite à la discussion dans les commentaires.
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
Ci-dessus, ce ./
marquer le début de chaque fichier signifie que nous pouvons clairement identifier où chaque nom de fichier commence (à ./
) et où il se termine (à la nouvelle ligne avant le prochain ./
ou la fin de la sortie).
Cela signifie que la sortie de du ./*
, contrairement à celle de du -- *
) peut être analysé de manière fiable, mais pas aussi facilement dans un script.
Cependant, lorsque la sortie est envoyée à un terminal, il existe de nombreuses autres façons dont un nom de fichier peut vous tromper :
-
Les caractères de contrôle, les séquences d'échappement peuvent affecter la façon dont les choses sont affichées. Par exemple,
r
déplace le curseur au début de la ligne,b
déplace le curseur vers l'arrière,e[C
vers l'avant (dans la plupart des terminaux)… -
de nombreux caractères sont invisibles sur un terminal en commençant par le plus évident :le caractère espace.
-
Certains caractères Unicode ressemblent exactement à la barre oblique dans la plupart des polices
$ printf 'u002f u2044 u2215 u2571 u29F8n' / ⁄ ∕ ╱ ⧸
(voir comment ça se passe dans votre navigateur).
Un exemple :
$ touch x 'x ' $'ybx' $'xn0t.u2215x' $'yr0t.e[Cx'
$ ln x y
$ du -hs ./*
0 ./x
0 ./x
0 ./x
0 .∕x
0 ./x
0 ./x
Beaucoup de x
‘s mais y
est manquant.
Certains outils comme GNU
ls remplacerait les caractères non imprimables par un point d'interrogation (notez que ∕
(U+2215) est cependant imprimable) lorsque la sortie va à un terminal. GNU du
pas.
Il existe des moyens de les faire se révéler :
$ ls
x x x?0?.∕x y y?0?.?[Cx y?x
$ LC_ALL=C ls
x x?0?.???x x y y?x y?0?.?[Cx
Découvrez comment ∕
tourné vers ???
après avoir dit ls
que notre jeu de caractères était ASCII.
$ du -hs ./* | LC_ALL=C sed -n l0t./x$0t./x $0t./x$0t.342210225x$0t./yr0t.