$ find -exec cd => dà errore: => trova: 'cd': nessun file o directory


8

Quando eseguo questo comando funziona:

$ 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

Tuttavia, quando si sostituisce lscon cdesso non funziona:

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

So che cdè un bashbuilt-in, quindi ho provato questo che non funziona neanche:

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

Come posso usare cdinsieme al find -execcomando?


AGGIORNARE

La ragione per cui sto cercando di utilizzare cdcon find -execè che il nome della directory è un tipo strano, che si presenta sul mio terminale come qualcosa di simile ????.


1
A proposito, è possibile LC_ALL=C printf '%q\n' *stampare i nomi ASCII per tutti i file nella directory corrente, uno a una riga (cambiando le nuove righe $'\n'o simili).
Charles Duffy,

Risposte:


15

L' -execopzione per findeseguire un'utilità esterna, possibilmente con alcune opzioni della riga di comando e altri argomenti.

Unix non fornisce cdun'utilità esterna, ma solo una shell integrata, quindi findnon riesce a eseguirla. Almeno MacOS e Solaris non forniscono cdcome un programma di utilità esterno.

Ci sarebbe poco o niente da fare per l'esecuzione cdin questo modo, tranne per verificare se il percorso trovato da findè una directory in cui si sarebbe in grado di farlo cd. La directory di lavoro nella shell interattiva (o qualunque cosa stia chiamando find) non cambierebbe comunque.

Relazionato:


Se riscontri problemi con il nome di una directory strano o estremamente difficile da digitare e desideri passare a quella directory, prendi in considerazione la possibilità di creare un link simbolico alla directory e quindi cdutilizzarla utilizzando quel link:

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

Ciò creerebbe un collegamento simbolico denominato thedirche indicherebbe la directory problematica. È quindi possibile modificare la directory di lavoro con

cd thedir

(se il collegamento esiste nella directory corrente). Questo evita di modificare la directory in alcun modo. Un'altra idea sarebbe quella di rinominare la directory in modo simile con find, ma ciò non sarebbe consigliabile se un altro programma prevede che la directory abbia quel nome particolare.


La ragione per cui ho intenzione di usare cdcon find -execè che i nomi delle directory sono in alcuni personaggi strani, che non appaiono correttamente sul mio terminale.
user3405291

@ user3405291 Non è chiaro dalla domanda che cosa ti aspetti che accada quando esegui il comando. Ti aspetti di cambiare directory nella shell interattiva?
Kusalananda

Sì, voglio solo cdentrare in una directory che ha un brutto nome e non posso entrarci cdin modo normale.
user3405291

@ user3405291 Vedi aggiornamento.
Kusalananda

La cosa divertente è che /bin/cdè il risultato di POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) in cui i normali builtin devono essere accessibili a exec (). Certo, /bin/cdprobabilmente non fa quello che la gente vuole :-)
Stephen Harris,

7

findesegue il -execcomando stesso, non comporta una shell. Anche se lo facesse, il cambio di directory persisterebbe solo fino alla chiusura della shell, subito dopo il cd.

Dovrai far uscire il nome del file dalla shell corrente cd. A seconda della gravità dei nomi dei file, è possibile utilizzare la sostituzione dei comandi:

cd "$(find . -inum 888696)"

Ciò non funzionerà se il nome file termina in una nuova riga, poiché la sostituzione dei comandi mangia nuove righe finali. In tal caso dovrai proteggere la nuova riga e sbarazzarti di quella findaggiunta durante la stampa:

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

Oppure, con GNU find, non stampare la nuova riga finale (ma proteggere comunque qualsiasi nel nome file):

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

Anche usando il -quitpredicato (anche un'estensione GNU), per smettere di occuparsi della prima partita come ottimizzazione.

In alternativa, potresti avviare una nuova shell dall'interno find, ma è un po 'brutta:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;

Ho provato il tuo trucco con "echo x", su directory che terminano con newline, ritorno a capo ed entrambi, senza successo.
Gerard H. Pille,

@ GerardH.Pille, oh, scusa, ho dimenticato la nuova riga findaggiunta durante la stampa. Modificato.
ilkkachu,

Se si sostituisce printf con uno print0, è possibile eseguire 'cd "$ dir"'.
Gerard H. Pille,

@ GerardH.Pille, forse. Ma Bash ignora qualsiasi byte nullo nell'input da una sostituzione di comando e rimuove la nuova riga finale solo dopo. Quindi dir=$(find -print0)continuerà a
eliminare

5

Non con exec, ma questo potrebbe essere abbastanza buono per te:

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

Il "tipo d", per essere sicuro. Di cosa, non lo so davvero.


Questo non riesce se il nome della directory termina con una nuova riga.
Kusalananda

Certo, ma le directory raramente lo fanno. Se provo a crearne uno su Linux ext4, ottengo un "errore di protocollo". Non pensi che sia una perdita di tempo?
Gerard H. Pille,

2
Bene, i nomi raramente hanno caratteri non stampabili, ma questo ovviamente lo fa.
Kusalananda

Quali filesystem consentono newline nei nomi di directory?
Gerard H. Pille,

1
@ GerardH.Pille, come hai provato? mkdir $'foo\n'funziona perfettamente qui; Devo ancora vedere un filesystem UNIX nativo in cui non era supportato.
Charles Duffy,

4

Utilizzare uno stream delimitato da NUL per leggere l'output findche funziona in tutti i casi, inclusi i nomi che terminano con una nuova riga. Inoltre, è possibile utilizzare printf '%q'per generare una rappresentazione leggibile di un nome file.

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

3

Se ricevi questo messaggio, la piattaforma del tuo sistema operativo è difettosa. Lo standard POSIX richiede che un comando denominato cddeve essere disponibile nel file system in modo che possa essere chiamato tramite exec().

Ora le cattive notizie per te:

Anche se la piattaforma del tuo sistema operativo non era buggy, semplicemente non hai visualizzato un avviso, ma non hai ottenuto i risultati previsti, poiché non ti aiuta se un programma separato cambia la sua directory di lavoro corrente e muore immediatamente dopo.

Se ti piace avere un cdcomando efficace eseguito da find, puoi fare qualcosa del tipo:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;

2
Questo è solo un bug se quella piattaforma rivendica la conformità POSIX. Avere un'utilità cd autonoma non è molto utile, quindi ha senso ignorare tale requisito altrimenti senza influire sull'usabilità della piattaforma. Si noti che lasciare un'espansione dei parametri non quotata ha un significato molto speciale in sh, non qualcosa che vorresti fare. È meglio evitare valori fittizi per quello script inline, $0come ad esempio quello utilizzato nei messaggi di errore (come quando cdfallirebbe).
Stéphane Chazelas,

Volevi dire cd "$1"? Se il nome è difficile da digitare, potrebbe anche contenere metacaratteri di shell ...
Toby Speight,

correggere questo è stato un errore di battitura
Schily
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.