$ find -exec cd => donne une erreur: => find: 'cd': Aucun fichier ou répertoire de ce type

8

Lorsque j'exécute cette commande, cela fonctionne:

$ find . -inum 888696 -exec ls '{}' \;
Conversation.pst  Outlook Data File  Outlook Data File.sbd  Trash      Unsent Messages
Inbox.pst     Outlook Data File.msf  Sent.pst       Trash.msf  Unsent Messages.msf

Cependant, lorsque le remplacer lspar cdcela ne fonctionne pas :

$ find . -inum 888696 -exec cd '{}' \;
find: cd’: No such file or directory

Je sais que cdc'est un bashintégré, j'ai donc essayé cela qui ne fonctionne pas non plus:

$ find . -inum 888696 -exec builtin cd '{}' \;
find: builtin’: No such file or directory

Comment puis-je utiliser cdavec la find -execcommande?


MISE À JOUR

La raison pour laquelle je suis en train d'utiliser cdavec find -execest que le nom du répertoire est un étrange qui apparaît sur mon terminal comme quelque chose comme ????.

user3405291
la source
1
BTW, vous pouvez LC_ALL=C printf '%q\n' *imprimer les noms ASCII de tous les fichiers de votre répertoire actuel, un sur une ligne (en changeant les retours à la ligne $'\n'ou similaires).
Charles Duffy

Réponses:

15

L' -execoption pour findexécuter un utilitaire externe, éventuellement avec une option de ligne de commande et d'autres arguments.

Votre Unix ne fournit pas en cdtant qu'utilitaire externe, uniquement en tant que shell intégré, donc findne parvient pas à l'exécuter. Au moins macOS et Solaris ne fournir cdcomme un utilitaire externe.

Il serait peu ou pas utile de l'exécuter cdde cette manière, sauf pour tester si le chemin d'accès trouvé par findest un répertoire dans lequel vous pourriez le faire cd. Le répertoire de travail dans votre shell interactif (ou quoi que ce soit qui appelle find) ne changerait pas de toute façon.

En relation:


Si vous rencontrez des problèmes avec le nom d'un répertoire étrange ou extrêmement difficile à taper, et que vous souhaitez passer à ce répertoire, envisagez de créer un lien symbolique vers le répertoire, puis cdà l'intérieur en utilisant ce lien à la place:

find . -inum 888696 -exec ln -s {} thedir ';'

Cela créerait un lien symbolique nommé thedirqui pointerait vers le répertoire problématique. Vous pouvez ensuite modifier le répertoire de travail avec

cd thedir

(si le lien existe dans le répertoire courant). Cela évite de modifier le répertoire en aucune façon. Une autre idée serait de renommer le répertoire de la même manière avec find, mais ce ne serait pas conseillé si un autre programme s'attend à ce que le répertoire ait ce nom particulier.

Kusalananda
la source
La raison pour laquelle j'ai l'intention d'utiliser cdavec find -execest que les noms de répertoire sont en caractères étranges qui ne s'affichent pas correctement sur mon terminal.
user3405291
@ user3405291 Il n'est pas clair à la question de savoir ce que vous attendez lorsque vous exécutez la commande. Vous attendez-vous à changer de répertoire dans le shell interactif?
Kusalananda
Oui, je veux juste cdentrer dans un répertoire qui a un mauvais nom, et je ne peux pas y cdentrer normalement.
user3405291
@ user3405291 Voir mise à jour.
Kusalananda
Ce qui /bin/cdest drôle, c'est que c'est le résultat de POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) où les fonctions internes normales doivent être accessibles à exec (). Bien sûr, /bin/cdne fait probablement pas ce que les gens veulent :-)
Stephen Harris
7

findexécute la -execcommande elle-même, elle n'implique pas de shell. Même si c'était le cas, le changement de répertoire ne persisterait que jusqu'à la fermeture de ce shell, immédiatement après le cd.

Vous devrez récupérer le nom du fichier dans le shell actuel cd. Selon la gravité de vos noms de fichiers, vous pouvez utiliser la substitution de commandes:

cd "$(find . -inum 888696)"

Cela ne fonctionnera pas si le nom de fichier se termine par une nouvelle ligne, car la substitution de commandes mange les nouvelles lignes de fin. Dans ce cas, vous devez protéger la nouvelle ligne et vous débarrasser de celle findajoutée lors de l'impression:

dir=$(find . -inum 888696; echo x)
cd "${dir%?x}"

Ou, avec GNU find, n'imprimez pas la nouvelle ligne de fin (mais protégez-en tout dans le nom de fichier):

dir=$(find . -inum 888696 -printf "%px" -quit)
cd "${dir%x}"

Utiliser également le -quitprédicat (également une extension GNU) pour arrêter de chercher la première correspondance comme une optimisation.

Alternativement, vous pouvez démarrer un nouveau shell de l'intérieur find, mais c'est un peu moche:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;
ilkkachu
la source
J'ai essayé votre astuce avec le "echo x", sur les répertoires se terminant par la nouvelle ligne, le retour chariot et les deux, sans succès.
Gerard H.Pille
@ GerardH.Pille, oh, désolé, j'ai oublié la nouvelle ligne ajoutée findlors de l'impression. Édité.
ilkkachu
Si vous remplacez printf par print0, vous pouvez faire 'cd "$ dir"'.
Gerard H.Pille
@ GerardH.Pille, peut-être. Mais Bash ignore tous les octets nuls en entrée d'une substitution de commande et ne supprime la nouvelle ligne de fin qu'après cela. Il en dir=$(find -print0)sera de même pour la nouvelle ligne de fin du nom de fichier ...
ilkkachu
5

Pas avec exec, mais cela peut être suffisant pour vous:

cd "$(find . -inum 888696 -type d)"

Le "-type d", juste pour être sûr. De quoi, je ne sais pas vraiment.

Gerard H. Pille
la source
Cela échoue si le nom du répertoire se termine par une nouvelle ligne.
Kusalananda
Bien sûr, mais les répertoires le font rarement. Si j'essaye d'en créer un sur un Linux ext4, j'obtiens une "erreur de protocole". Ne pensez-vous pas que c'est une perte de temps?
Gerard H.Pille
2
Eh bien, les noms ont rarement des caractères non imprimables, mais celui-ci en a évidemment.
Kusalananda
Quels systèmes de fichiers autorisent les sauts de ligne dans les noms de répertoire?
Gerard H.Pille
1
@ GerardH.Pille, comment avez-vous testé cela? mkdir $'foo\n'fonctionne parfaitement ici; Je n'ai pas encore vu de système de fichiers UNIX natif où il n'était pas pris en charge.
Charles Duffy
4

Utilisez un flux délimité par NUL pour lire la sortie findqui fonctionne dans tous les cas - y compris les noms qui se terminent par des retours à la ligne. Vous pouvez également utiliser printf '%q'pour générer une représentation lisible d'un nom de fichier.

inum=888696
if IFS= read -r -d '' filename < <(find . -inum "$inum" -print0); then
  LC_ALL=C printf 'Located filename: %q\n' "$filename" >&2
  cd -- "$filename"
else
  echo "No file located for inode $inum" >&2
fi
Charles Duffy
la source
3

Si vous obtenez ce message, votre plate-forme OS est boguée. La norme POSIX requiert qu'une commande nommée cdsoit disponible dans le système de fichiers pour pouvoir être appelée via exec().

Maintenant, la mauvaise nouvelle pour vous:

Même si votre plate-forme de système d'exploitation n'était pas boguée, vous n'avez tout simplement pas vu d'avertissement, mais vous n'avez pas obtenu les résultats attendus, car cela ne vous aide pas si un programme distinct change son répertoire de travail actuel et meurt immédiatement après cela.

Si vous aimez avoir un efficace cddans une commande exécutée par find, vous pouvez faire quelque chose comme:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;
schily
la source
2
Ce n'est qu'un bogue si cette plate-forme revendique la conformité POSIX. Avoir un utilitaire cd autonome n'est pas très utile, il est donc logique d'ignorer cette exigence sinon sans affecter l'utilisation de la plate-forme. Notez que laisser une extension de paramètre sans guillemets a une signification très spéciale dans sh, pas quelque chose que vous voudriez faire. Il vaut mieux éviter les valeurs fictives pour ce script en ligne $0car il est utilisé dans les messages d'erreur par exemple (comme quand cela cdéchouerait).
Stéphane Chazelas
Vous vouliez dire cd "$1"? Si le nom est difficile à taper, il peut aussi contenir des métacaractères shell ...
Toby Speight
corriger c'était une faute de frappe
schily