$ find -exec cd => gibt einen Fehler aus: => find: 'cd': Keine solche Datei oder kein solches Verzeichnis

8

Wenn ich diesen Befehl ausführe, funktioniert es:

$ 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

Allerdings Beim Austausch lsmit cdihm funktioniert nicht funktioniert:

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

Ich weiß, dass cdes basheingebaut ist, also habe ich es versucht, was auch nicht funktioniert:

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

Wie kann ich cdzusammen mit find -execBefehl verwenden?


AKTUALISIEREN

Der Grund , warum ich versuchen zu verwenden , cdmit find -exec, dass der Verzeichnisname ein seltsames ist , die zeigt , auf meinem Terminal als so etwas wie ????.

user3405291
quelle
1
Übrigens können Sie LC_ALL=C printf '%q\n' *ASCII-Namen für alle Dateien in Ihrem aktuellen Verzeichnis drucken, eine in eine Zeile (Ändern von Zeilenumbrüchen in $'\n'oder ähnliches).
Charles Duffy

Antworten:

15

Die -execOption zum findAusführen eines externen Dienstprogramms, möglicherweise mit einer Befehlszeilenoption und anderen Argumenten.

Ihr Unix wird nicht cdals externes Dienstprogramm bereitgestellt, sondern nur als integrierte Shell. findDaher kann es nicht ausgeführt werden. Mindestens macOS und Solaris Sie bieten cdals externes Dienstprogramm.

Es würde wenig oder gar keine Verwendung für die Ausführung cdauf diese Weise geben, außer um zu testen, ob der von gefundene Pfadname findein Verzeichnis ist, in das Sie gelangen könnten cd. Das Arbeitsverzeichnis in Ihrer interaktiven Shell (oder was auch immer aufgerufen wird find) würde sich sowieso nicht ändern.

Verbunden:


Wenn Sie Probleme mit dem Namen eines Verzeichnisses haben, das seltsam oder äußerst schwierig einzugeben ist, und Sie in dieses Verzeichnis wechseln möchten, sollten Sie einen symbolischen Link zum Verzeichnis erstellen und cdstattdessen diesen Link verwenden:

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

Dies würde einen symbolischen Link mit dem Namen erstellen thedir, der auf das problematische Verzeichnis verweist. Sie können dann das Arbeitsverzeichnis mit ändern

cd thedir

(wenn der Link im aktuellen Verzeichnis vorhanden ist). Dadurch wird vermieden, dass das Verzeichnis in irgendeiner Weise geändert wird. Eine andere Idee wäre, das Verzeichnis auf ähnliche Weise mit umzubenennen find, aber das wäre nicht ratsam, wenn ein anderes Programm erwartet, dass das Verzeichnis diesen bestimmten Namen hat.

Kusalananda
quelle
Der Grund , warum ich Absicht zu verwenden , cdmit find -exec, dass die Verzeichnisnamen in einigen seltsamen Zeichen sind , die korrekt auf meinem Terminal nicht angezeigt.
user3405291
@ user3405291 Aus der Frage geht nicht hervor, was Sie erwarten, wenn Sie den Befehl ausführen. Erwarten Sie, das Verzeichnis in der interaktiven Shell zu wechseln?
Kusalananda
Ja, ich möchte nur cdin ein Verzeichnis gehen, das einen schlechten Namen hat, und ich kann es nicht cdauf normale Weise betreten.
user3405291
@ user3405291 Siehe Update.
Kusalananda
Witzig ist, dass dies /bin/cdein Ergebnis von POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) ist, bei dem die normalen Builds für exec () zugänglich sein müssen. Natürlich macht /bin/cdwahrscheinlich nicht, was die Leute wollen :-)
Stephen Harris
7

findführt den -execBefehl selbst aus, es handelt sich nicht um eine Shell. Selbst wenn dies der Fall wäre, würde der Verzeichniswechsel nur so lange bestehen bleiben, bis diese Shell unmittelbar nach dem beendet wird cd.

Sie müssen den Dateinamen in die aktuelle Shell übertragen, um ihn cdzu speichern. Abhängig davon, wie schlecht Ihre Dateinamen sind, können Sie die Befehlsersetzung verwenden:

cd "$(find . -inum 888696)"

Dies funktioniert nicht, wenn der Dateiname in einer neuen Zeile endet, da die Befehlsersetzung nachfolgende Zeilenumbrüche verschlingt. In diesem Fall müssten Sie die neue Zeile schützen und die findbeim Drucken hinzugefügte entfernen :

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

Oder lassen Sie mit GNU finddie nachfolgende neue Zeile nicht drucken (schützen Sie jedoch alle im Dateinamen):

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

Verwenden Sie auch das -quitPrädikat (auch eine GNU-Erweiterung), um die erste Übereinstimmung nicht mehr als Optimierung zu betrachten.

Alternativ können Sie eine neue Shell von innen starten find, aber es ist ein bisschen hässlich:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;
ilkkachu
quelle
Versuchte deinen Trick mit dem "echo x" in Verzeichnissen, die mit Zeilenumbruch, Wagenrücklauf und beidem enden, ohne Erfolg.
Gerard H. Pille
@ GerardH.Pille, oh, sorry, ich habe vergessen, dass die Newline findselbst beim Drucken hinzugefügt wird . Bearbeitet.
Ilkkachu
Wenn Sie den printf durch einen print0 ersetzen, können Sie 'cd "$ dir"' ausführen.
Gerard H. Pille
@ GerardH.Pille vielleicht. Bash ignoriert jedoch alle von einer Befehlsersetzung eingegebenen Nullbytes und entfernt die nachfolgende neue Zeile erst danach. Also dir=$(find -print0)wird immer noch die nachfolgende Newline des Dateinamens in den Papierkorb werfen ...
ilkkachu
5

Nicht mit exec, aber das kann gut genug für Sie sein:

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

Der "-Typ d", nur um sicherzugehen. Von was weiß ich nicht wirklich.

Gerard H. Pille
quelle
Dies schlägt fehl, wenn der Name des Verzeichnisses mit einem Zeilenumbruch endet.
Kusalananda
Sicher, aber Verzeichnisse tun dies selten. Wenn ich versuche, eine unter Linux ext4 zu erstellen, wird "Protokollfehler" angezeigt. Denken Sie nicht, dass dies Zeitverschwendung ist?
Gerard H. Pille
2
Nun, Namen haben selten nicht druckbare Zeichen, aber dieses tut es offensichtlich.
Kusalananda
Welche Dateisysteme erlauben Zeilenumbrüche in Verzeichnisnamen?
Gerard H. Pille
1
@ GerardH.Pille, wie hast du das getestet? mkdir $'foo\n'funktioniert hier perfekt; Ich habe noch kein natives UNIX-Dateisystem gesehen, in dem es nicht unterstützt wurde.
Charles Duffy
4

Verwenden Sie einen durch NUL getrennten Stream, um die Ausgabe zu lesen find, die in allen Fällen funktioniert - einschließlich Namen, die in Zeilenumbrüchen enden. Sie können auch printf '%q'eine lesbare Darstellung eines Dateinamens erstellen.

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
quelle
3

Wenn Sie diese Meldung erhalten, ist Ihre Betriebssystemplattform fehlerhaft. Der POSIX-Standard verlangt, dass ein benannter Befehl cdim Dateisystem verfügbar sein muss, damit er über aufgerufen werden kann exec().

Nun die schlechten Nachrichten für Sie:

Selbst wenn Ihre Betriebssystemplattform nicht fehlerhaft war, haben Sie keine Warnung gesehen, aber Sie haben nicht die erwarteten Ergebnisse erhalten, da es Ihnen nicht hilft, wenn ein separates Programm sein aktuelles Arbeitsverzeichnis ändert und sofort danach stirbt.

Wenn Sie einen effektiven cdBefehl ausführen möchten find, können Sie Folgendes tun:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;
schily
quelle
2
Dies ist nur dann ein Fehler, wenn diese Plattform die POSIX-Konformität beansprucht. Ein eigenständiges CD-Dienstprogramm ist nicht sehr nützlich, daher ist es sinnvoll, diese Anforderung ansonsten zu ignorieren, ohne die Benutzerfreundlichkeit der Plattform zu beeinträchtigen. Beachten Sie, dass das shNicht- Zitieren einer Parametererweiterung eine ganz besondere Bedeutung hat und nicht etwas, das Sie tun möchten. Es ist besser, Dummy- Werte für diese Inline -Skripte zu vermeiden , $0da diese beispielsweise in Fehlermeldungen verwendet werden (z. B. wenn cddies fehlschlagen würde).
Stéphane Chazelas
Meinten Sie cd "$1"? Wenn der Name schwer zu tippen ist, kann er auch Shell-Metazeichen enthalten ...
Toby Speight
Richtig, dies war ein Tippfehler
6.