Dans un script que j'utilise find
pour collecter des fichiers dans le répertoire courant, comme dans
$ find . -name "*.h"
./foo.h
Maintenant, je voudrais juste le sortir foo.h
, sans le ./
préfixe. Je pensais que la chaîne vide ""
dénotait le répertoire courant dans les commandes shell. Mais cela donne:
$ find "" -name "*.h"
find: ftsopen: No such file or directory
J'avais donc tort. Maintenant ma question est quand / comment / où / .. une "chaîne vide (?)" Désigne-t-elle le répertoire courant dans les commandes qui attendent un nom de fichier ou un chemin? Y a-t-il une explication nette et éclairante?
Une question secondaire est de savoir si la découverte au-dessus peut être résolue simplement, sans manipulation de chaîne à la ${parameter#word}
ou cut
ou sed
?
find
a le paramètre -printf pour manipuler la façon dont les résultats sont affichés.find . -name '*.h' -printf '%P\n'
supprimera le./
préfixe. Voyez ce quefind . -name '*.h' -print
ça fait.-printf
option. FWIW,strings
sur ma trouvaille donne@(#)PROGRAM:find PROJECT:shell_cmds-175
?!?Réponses:
Il y a longtemps (dans la 7e édition , 32V , 4.2BSD , 4.3BSD ), au niveau de l'appel système, un chemin d'accès de longueur nulle désignait le répertoire de travail actuel (lorsqu'il était utilisé pour la recherche; il n'était pas autorisé lors de la tentative de création ou de suppression d'un fichier ou répertoire). Dans System III , c'était une erreur d'utiliser un chemin d'accès de longueur nulle dans toutes les circonstances, et la norme POSIX a ceci à dire à propos de la résolution du nom de chemin:
la source
dir/
est essentiellement le même quedir/.
Vous pouvez utiliser:
Notez que les fichiers du répertoire actuel dont le nom commence par
.
seront omis et que les fichiers dont le nom commence par-
seront interprétés comme des options parfind
et provoquent des ravages, ce n'est donc pas un équivalent général defind . …
.L'absence d'une chaîne se terminant par "
/
" dans le cadre d'un nom de fichier implique le répertoire en cours, mais cela ne signifie pas que le répertoire en cours est indiqué par une chaîne vide (ce qui n'est sans doute pas la même chose que l'absence d'une chaîne, bien qu'il puisse ressembler à l'impression).la source
En général, la chaîne vide ne désigne pas le répertoire courant, ni pour les commandes shell ni dans les appels système. C'était le cas sur certains systèmes plus anciens, mais pas sur les systèmes compatibles POSIX .
Parfois, vous trouverez un programme qui utilise le répertoire actuel lorsque vous passez une chaîne vide et que le programme attend un nom de répertoire. Cela est parfois délibéré, et parfois un effet secondaire de l'ajout du chemin absolu du répertoire actuel lorsque la chaîne donnée ne commence pas par une barre oblique.
La meilleure chose pour vous serait de quitter le
./
. Cela ne fait aucun mal.Si la liste des fichiers est pour
Notez que cela modifie certains noms de fichiers contenant des retours à la ligne. Ce n'est généralement pas un problème pour la consommation humaine, et la sortie de
find
ne convient pas à la consommation de programme car elle est ambiguë. Si vous utilisez-print0
, ce qui convient à la consommation du programme, vous ne vous souciez probablement pas du./
préfixe de toute façon.Vous pouvez utiliser à la
find * …
place defind . …
, mais notez qu'ilfind *
présente un certain nombre de défauts qui le rendent généralement inapproprié:.
est omis..
ou ..`) sont omis.-
(ou un fichier appelé!
ou(
...), il sera interprété comme une option ou un prédicat parfind
.Le premier point n'a pas d'importance si votre filtre exclut le répertoire actuel. Pour le deuxième point, vous pouvez utiliser les modèles
..?* .[!.]* *
pour faire correspondre tous les fichiers du répertoire en cours, mais vous devrez vérifier si chaque modèle correspond à au moins un fichier et l'omettre s'il ne le fait pas. C'est possible mais très lourd. Le dernier point est un bouchon. Celafind *
peut donc convenir à une utilisation en ligne de commande rapide, mais ne l'utilisez pas dans un script.Une autre approche consiste à utiliser la fonction de globulation récursive du shell, par exemple
Cela doit être activé par
shopt -s globstar
dans bash et parset -o globstar
dans ksh93, et n'existe pas dans un shell POSIX de base tel que dash. Les fichiers de points ne seront pas traversés par défaut; pour les inclure, assurez-vous d'abord de ne pas ignorer les fichiers dot avecshopt -s dotglob
en bash ouFIGNORE='@(.|..)'
en ksh93. De plus, s'il n'y a pas de correspondance, cette commande imprime le motif; exécutezshopt -s nullglob
en bash pour imprimer une ligne vide à la place et utilisez le modèle~(N)**/*.h
dans ksh.Dans zsh, la globalisation récursive est activée par défaut. Utilisez le qualificatif glob
D
pour inclure des fichiers de points etN
pour imprimer une ligne vide s'il n'y a pas de correspondance (par défaut, zsh renvoie une erreur si un motif ne correspond à aucun fichier). Vous pouvez utiliserprintf
comme ci-dessus oula source
find *
sont nouveaux pour moi, et certains sont effrayants !!Je ne peux penser à aucun exemple où la chaîne vide indique le répertoire courant
.
. Vous pensez peut-être à des invocations commels
, mais c'est parce quels
suppose le répertoire courant si aucun paramètre n'est donné, et en fait il ne prendra pas la chaîne vide:la source
PATH
composant.Il existe différentes astuces que vous pouvez utiliser pour obtenir la sortie de find sans le début
./
:Utilisez l'
-printf
option de recherche et dites-lui d'imprimer uniquement%f
. Voirman find
:Par exemple:
Analyser la sortie:
@ Le tour d'Anthon
Quant à votre autre question, la chaîne vide ne désigne jamais le répertoire courant. C'est juste que divers programmes prennent le répertoire courant par défaut, donc quand vous les exécutez sans arguments, ils sont exécutés sur le répertoire courant.
la source
find
. Ou utilisez%P
uniquement pour dépouiller le./
find * -name '*.h'
trouverafoo/.bar.h
, mais pas.bar.h
dans le répertoire courant.Si les fichiers sont dans le répertoire courant, vous pouvez simplement utiliser
ls
:Si vous voulez également les fichiers dans les sous-répertoires et que vous avez juste besoin du nom de fichier, vous pouvez faire quelque chose comme:
Il existe des commandes qui obtiendront l'absence de chaîne comme répertoire courant, mais essentiellement parce qu'elles obtiendront le répertoire courant par défaut si rien n'est entré. Le
.
dénote toujours..
le répertoire courant (et le répertoire parent)la source
find
solution supprime tous les composants du répertoire