$ find -exec cd => da error: => find: 'cd': No existe tal archivo o directorio

8

Cuando ejecuto este comando funciona:

$ 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

Sin embargo, Al sustituir lscon cdno funciona:

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

Sé que cdes un bashbuilt-in, así que probé esto lo que hace que no funciona bien:

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

¿Cómo puedo usar cdjunto con el find -execcomando?


ACTUALIZAR

La razón por la que estoy tratando de utilizar cdcon find -execes que el nombre del directorio es extraña, que aparece en mi terminal como algo parecido ????.

usuario3405291
fuente
1
Por cierto, puede LC_ALL=C printf '%q\n' *imprimir nombres ASCII para todos los archivos en su directorio actual, uno a una línea (cambiando líneas nuevas $'\n'o similares).
Charles Duffy

Respuestas:

15

La -execopción de findejecutar una utilidad externa, posiblemente con alguna opción de línea de comando y otros argumentos.

Su Unix no se proporciona cdcomo una utilidad externa, solo como un shell incorporado, por lo que findno puede ejecutarlo. Al menos MacOS y Solaris no proporcionar cdcomo una utilidad externa.

Sería de poca o ninguna utilidad ejecutar cdde esta manera, excepto como una forma de probar si el nombre de ruta encontrado por findes un directorio en el que podría hacerlo cd. El directorio de trabajo en su shell interactivo (o lo que sea que esté llamando find) no cambiaría de todos modos.

Relacionado:


Si tiene problemas con el nombre de un directorio que es extraño o extremadamente difícil de escribir, y desea cambiar a ese directorio, considere crear un enlace simbólico al directorio y luego cdusarlo en su lugar:

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

Esto crearía un enlace simbólico llamado thedirque apuntaría al directorio problemático. Luego puede cambiar el directorio de trabajo con

cd thedir

(si el enlace existe en el directorio actual). Esto evita modificar el directorio de ninguna manera. Otra idea sería cambiar el nombre del directorio de manera similar find, pero eso no sería aconsejable si otro programa espera que el directorio tenga ese nombre en particular.

Kusalananda
fuente
La razón por la que la intención de usar cdcon find -execes que los nombres de directorio son en algunos extraños personajes que no aparecen correctamente en mi terminal.
user3405291
@ user3405291 De la pregunta no queda claro qué espera que suceda cuando ejecuta el comando. ¿Espera cambiar el directorio en el shell interactivo?
Kusalananda
Sí, solo quiero cdingresar a un directorio que tiene un nombre incorrecto , y no puedo cdingresarlo de manera normal.
user3405291
@ user3405291 Ver actualización.
Kusalananda
Lo curioso es que /bin/cdes el resultado de POSIX ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) donde las funciones normales deben estar accesibles para exec (). Por supuesto, /bin/cdprobablemente no haga lo que la gente quiere :-)
Stephen Harris
7

findejecuta el -execcomando en sí, no involucra un shell. Incluso si lo hiciera, el cambio de directorio solo persistiría hasta que salga ese shell, inmediatamente después del cd.

Tendrá que llevar el nombre del archivo al shell actual para que entre cden él. Dependiendo de qué tan malos sean sus nombres de archivo, puede usar la sustitución de comandos:

cd "$(find . -inum 888696)"

Eso no funcionará si el nombre de archivo termina en una nueva línea, ya que la sustitución de comandos se come en las nuevas líneas finales. En ese caso, deberá proteger la nueva línea y deshacerse de la que se findagrega al imprimir:

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

O, con GNU find, haga que no imprima la nueva línea final (pero que aún proteja alguna en el nombre del archivo):

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

También usando el -quitpredicado (también una extensión GNU), para dejar de cuidar la primera coincidencia como una optimización.

Alternativamente, puede iniciar un nuevo shell desde dentro find, pero es un poco feo:

find . -inum 888696 -exec bash -c 'cd "$1" && exec bash' sh {} \;
ilkkachu
fuente
Intenté su truco con el "echo x", en directorios que terminaban con nueva línea, retorno de carro y ambos, sin éxito.
Gerard H. Pille
@ GerardH.Pille, oh, lo siento, olvidé que la nueva línea findagrega al imprimir. Editado
ilkkachu
Si reemplaza printf por print0, puede hacer 'cd "$ dir"'.
Gerard H. Pille
@ GerardH.Pille, tal vez. Pero Bash ignora los bytes nulos en la entrada de una sustitución de comando, y elimina la nueva línea final solo después de eso. Así dir=$(find -print0)que seguirá tirando la nueva línea del nombre del archivo ...
ilkkachu
5

No con el ejecutivo, pero esto puede ser lo suficientemente bueno para ti:

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

El "tipo d", solo para estar seguro. De qué, no sé realmente.

Gerard H. Pille
fuente
Esto falla si el nombre del directorio termina con una nueva línea.
Kusalananda
Claro, pero los directorios rara vez lo hacen. Si intento crear uno en un linux ext4, obtengo un "error de protocolo". ¿No crees que esto es una pérdida de tiempo?
Gerard H. Pille
2
Bueno, los nombres rara vez tienen caracteres no imprimibles, pero este obviamente los tiene.
Kusalananda
¿Qué sistemas de archivos permiten nuevas líneas en los nombres de directorio?
Gerard H. Pille
1
@ GerardH.Pille, ¿cómo probaste eso? mkdir $'foo\n'funciona perfectamente aquí; Todavía tengo que ver un sistema de archivos UNIX nativo donde no era compatible.
Charles Duffy
4

Utilice una secuencia delimitada por NUL para leer la salida de findque funciona en todos los casos, incluidos los nombres que terminan en nuevas líneas. Además, puede usar printf '%q'para generar una representación legible de un nombre de archivo.

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

Si recibe este mensaje, la plataforma de su sistema operativo tiene errores. El estándar POSIX requiere que un comando nombrado cddebe estar disponible en el sistema de archivos para que se pueda llamar a través de exec().

Ahora las malas noticias para ti:

Incluso si su plataforma de sistema operativo no tenía errores, simplemente no vio una advertencia, pero no obtuvo los resultados esperados, ya que no le ayuda si un programa separado cambia su directorio de trabajo actual e inmediatamente muere después de eso.

Si desea tener un cdcomando efectivo ejecutado por find, puede hacer algo como:

find . -type d -exec sh -c 'cd "$1"; some other command' dummy {} \;
astuto
fuente
2
Eso es solo un error si esa plataforma reclama conformidad POSIX. Tener una utilidad de CD independiente no es muy útil, por lo que tiene sentido ignorar ese requisito de lo contrario sin que afecte a la usabilidad de la plataforma. Tenga en cuenta que dejar una expansión de parámetro sin comillas tiene un significado muy especial sh, no es algo que desee hacer. Es mejor evitar valores ficticios para ese script en línea, $0ya que se usa en los mensajes de error, por ejemplo (como cuando eso cdfallaría).
Stéphane Chazelas
Quiso decir cd "$1"? Si el nombre es difícil de escribir, también puede contener metacaracteres de shell ...
Toby Speight
correcto esto fue un error tipográfico
schily