2010-08-11 20 views
15

En un script de shell, ¿cómo encontraría un archivo con un nombre en particular y luego navegaría a ese directorio para realizar más operaciones en él?Busque el archivo y cd a ese directorio en Linux

Desde aquí voy a copiar el archivo a través de otro directorio (pero no puedo hacer que ya sólo añadir que en el de contexto.)

+0

hallazgo y localizar :) pero no puede localizar hallazgo locatedb ?? – Candyfloss

+0

así que lea 'man 8 updatedb' – msw

+0

Hola candyfloss, por favor revise esto, acabo de publicar algo que resumiría como una solución extremadamente conveniente para este problema. Por favor revisa mi solución de cdf. :-) –

Respuesta

17

Usted puede usar algo como:

pax[/home/pax]> cd "$(dirname "$(find/-type f -name ls | head -1)")" 
pax[/usr/bin]> _ 

Este localizará el primer archivo regular ls y luego cambiará a ese directorio.

En términos de lo que hace cada bit:

  • El hallazgo se iniciará a las / y buscar hacia abajo, listando todos los archivos regulares (-type f) llamó ls (-name ls). Hay otras cosas que puede agregar al find para restringir aún más los archivos que obtiene.
  • La tubería a través de head -1 filtrará todas excepto la primera.
  • $() es una forma de tomar la salida de un comando y ponerlo en la línea de comando para otro comando.
  • dirname puede tomar una especificación de archivo completo y darle el bit de ruta.
  • cd simplemente cambia a ese directorio.

Si se ejecuta cada bit en la secuencia, se puede ver lo que sucede:

pax[/home/pax]> find/-type f -name ls 
/usr/bin/ls 

pax[/home/pax]> find/-type f -name ls | head -1 
/usr/bin/ls 

pax[/home/pax]> dirname "$(find/-type f -name ls | head -1)" 
/usr/bin 

pax[/home/pax]> cd "$(dirname "$(find/-type f -name ls | head -1)")" 

pax[/usr/bin]> _ 
+0

¿podría explicar lo que está pasando, por favor? – Candyfloss

+0

@Ross: seguro, ahí tienes. – paxdiablo

+1

Creo que necesitas un espacio entre '-type f' y' -name ls'. –

1

Si se acaba encontrando el archivo y luego moverlo a otra parte, sólo tiene que utilizar encontrar y -exec

find /path -type f -iname "mytext.txt" -exec mv "{}" /destination +; 
+1

Acabo de tener una situación similar en la que quería cambiar el nombre de las copias de los archivos con el mismo nombre en diferentes directorios. La opción '-execdir' de find me hizo el truco:' find. -name foo.txt -execdir mv "{}" bar.txt ";" 'cambia el nombre de foo.txt a bar.txt en cada directorio en el que se encuentra. –

0

Si se trata de un programa en su PATH, que puede hacer:

o en Bash:

cd "$(dirname "$(type -P ls)")" 

que utiliza uno menos ejecutable externo.

que no utiliza los factores externos:

dest=$(type -P ls); cd "${dest%/*}" 
+0

en que shell does' cd' no requiere comillas? Después de 'export d =" foo bar "; mkdir "$ d" ':' ksh -c 'cd $ d''se queja' cd: bad substitution'; 'ash -c 'cd $ d'' se queja: 'no puede cd a foo'; 'bash -c 'cd $ d'' se queja: 'cd: foo: No es un directorio'. – Gilles

+0

@Gilles: Podría haber jurado que funcionó en Bash. Editaré mi respuesta. –

+0

no puede funcionar en un shell que cumple con POSIX, 'cd' no tiene ninguna dispensa especial de las reglas de expansión habituales. Y todavía faltan las comillas sobre el argumento para 'dirname'. – Gilles

9

Lo siguiente debe ser más segura:

cd -- "$(find/-name ls -type f -printf '%h' -quit)" 

Ventajas:

  • El guión doble evita que la interpretación de un nombre de directorio a partir de un guión como opción (find no produce dichos nombres de archivo, pero no es dañino y podrían ser necesarias para construcciones similares)
  • -name cheque antes -type cheque porque este último a veces requiere un stat
  • Sin dirname necesario porque el %h especificador ya se imprime el nombre del directorio
  • -quit para detener la búsqueda después de que el primer archivo encontrado , por lo que no se requiere head lo que causaría que el script falle en los nombres de directorio que contienen nuevas líneas
+1

Para mí, esta es la mejor respuesta. Incluso se puede acortar para la mayoría de los casos y uno puede seguir el estilo: 1) hacer que el comando find encuentre lo que necesita, p. '$ encontrar. -nombre *.xsd' 2) agregue printf y -it '$ find. -name * .xsd -printf "% h" -quit' 3) surround by backtics y feed into cd (y ommit - si no es necesario): '$ cd \' find. -name * .xsd -printf "% h" -quit \ '' –

+0

la parte '-printf '% h'' hace que este comando realmente no devuelva nada, incluso si hay archivos ... no estoy seguro de por qué tho – Blauhirn

1
function fReturnFilepathOfContainingDirectory { 
    #fReturnFilepathOfContainingDirectory_2012.0709.18:19 
    #$1=File 

    local vlFl 
    local vlGwkdvlFl 
    local vlItrtn 
    local vlPrdct 

    vlFl=$1 
    vlGwkdvlFl=`echo $vlFl | gawk -F/ '{ $NF="" ; print $0 }'` 
    for vlItrtn in `echo $vlGwkdvlFl` ;do 
     vlPrdct=`echo $vlPrdct'/'$vlItrtn` 
    done 
    echo $vlPrdct 

} 
1

Ampliando respuestas ya dadas, si desea navegar de forma iterativa a todos los archivos que find localiza y realizar operaciones en cada directorio:

for i in $(find /path/to/search/root -name filename -type f) 
do (
    cd $(dirname $(realpath $i)); 
    your_commands; 
) 
done 
3

Basado en this answer a una pregunta similar, otra opción podría ser útil tener 2 comandos, 1ª encontrar el archivo y segundo para navegar a su directorio:

find ./ -name "champions.txt" 
cd "$(dirname "$(!!)")" 

Dónde !! es historia de la expansión significado 'el comando anterior'.

0

Simplemente así, ¿no es esto elegante?

cdf yourfile.py 

Por supuesto que necesita para su instalación en primer lugar, pero hay que hacerlo sólo una vez :

Agregar siguiente línea en su .bashrc o .zshrc, lo utiliza como su inicialización de shell guión.

source ~/bin/cdf.sh 

Y agregue este código en el archivo ~/bin/cdf.sh que necesita crear desde cero.

#!/bin/bash 

function cdf() { 
    THEFILE=$1 
    echo "cd into directory of ${THEFILE}" 
    # For Mac, replace find with mdfind to get it a lot faster. And it does not need args ". -name" part. 
    THEDIR=$(find . -name ${THEFILE} |head -1 |grep -Eo "/[ /._A-Za-z0-9\-]+/") 
    cd ${THEDIR} 
} 
0

Si el archivo es únicamente en un lugar que podría intentar lo siguiente:

cd "$(find ~/ -name [filename] -exec dirname {} \;)" && ...

Puede utilizar -exec para invocar dirname con el camino que encontrar rendimientos (que va a donde el marcador de posición {} es). Eso cambiará directorios. También puede agregar dobles ampersands (&&) para ejecutar el próximo comando después de que el shell haya cambiado de directorio.

Por ejemplo:
cd "$(find ~/ -name need_to_find_this.rb -exec dirname {} \;)" && ruby need_to_find_this.rb

Se buscará ese archivo rubí, cambiar al directorio, a continuación, ejecutarlo desde dentro de esa carpeta. Este ejemplo supone que el nombre de archivo es único y que, por alguna razón, el script ruby ​​debe ejecutarse desde su directorio. Si el nombre de archivo no es único, obtendrá muchas ubicaciones pasadas a cd, se devolverá un error y luego no cambiará los directorios.

1

nadie sugiriendo locate (que es mucho más rápido para árboles grandes)?

zsh:

cd $(locate zoo.txt|head -1)(:h) 
cd ${$(locate zoo.txt)[1]:h} 
cd ${$(locate -r "/zoo.txt$")[1]:h} 

or could be slow 

cd **/zoo.txt(:h) 

bash:

cd $(dirname $(locate -l1 -r "/zoo.txt$")) 
Cuestiones relacionadas