2010-03-11 40 views
30

estoy usando hallazgo para una tarea y me di cuenta de que cuando hago algo como esto:¿Por qué usar el comando dirname en find da puntos para cada coincidencia?

find `pwd` -name "file.ext" -exec echo $(dirname {}) \; 

que le dará puntos única para cada partido. Cuando sustituye dirname con basename en ese comando, obtiene las rutas completas. ¿Estoy jodiendo algo aquí o es este comportamiento esperado? Estoy acostumbrado a basename que le da el nombre del archivo (en este caso file.ext) y dirname que le da el resto de la ruta.

Respuesta

24

Considérese el siguiente script:

#!/bin/sh 
set -x 
find `pwd` -name "file.ext" -exec echo $(dirname {}) \; 

set -x muestra cómo las obras de ampliación y lo que la orden final es. Cuando se ejecuta, da el siguiente resultado:

++ pwd 
++ dirname '{}' 
+ find /home/kibab -name file.ext -exec echo . ';' 

Por lo tanto, lo primero que se expande es la pwd. El segundo es $(dirname {}). El resultado de esos dos comandos se coloca en el comando find. Por lo tanto, está diciendo find al -exec echo ., por lo que está viendo el resultado esperado.

Cuando sustituyes basename para dirname, la expansión tiene lugar todavía, pero los resultados de la expansión son diferentes:

  1. pwd se expande a la ruta actual. En mi ejemplo anterior, el resultado es /home/kibab
  2. basename {} se ejecuta. El resultado de este comando es {}.
  3. El comando buscar se ejecuta con las sustituciones anteriores en su lugar. El último comando ejecutado se ve así:

    find /home/kibab -name '*.png' -exec echo '{}' ';'

Al inspeccionar el comando anterior, se dará cuenta que el comando ahora simplemente eco de cualquier archivo fue encontrado.

¿Quizás quieres algo como esto?

find `pwd` -name "file.ext" -printf "%f\n" 
+0

@ Martin - Buen punto, explicación agregada. –

+0

Esto ayudó mucho. No sabía acerca de set -x, y el único contexto que he usado basename/dirname fue cuando lo estaba configurando en una variable. – temp2290

+0

Es posible que desee echar un vistazo a 'set -v' y algunas de las otras opciones del conjunto también. Buena suerte. –

4

No sé por qué recibe eso, sino que intento esto:

find `pwd` -name file.ext |xargs -l1 dirname 
+0

Esto en realidad ayudó, aunque tuve que reemplazar el 'l' minúsculo por uno mayúsculo. ¿Por qué funciona esto como se esperaba, pero '... | xargs dirname' no? –

0

Esto se debe a find grabados rutas relativas a la ruta que busca desde. Si intentaste esta búsqueda desde /, obtendrías `` pwd \ para cada ruta.

4

$(dirname {}) es evaluado por el shell antes de pasarse al find. El resultado de esta evaluación es ., por lo que solo está diciendo find para ejecutar echo . por cada archivo que encuentre.

basename {} evalúa a {}, así que con $(basename {}) sustituido por $(dirname {}), find ejecutará echo {} para cada archivo. Esto da como resultado el nombre completo de cada archivo que se repite.

Si desea emitir el resultado de dirname para cada archivo encontrado, se puede omitir el echo:

find `pwd` -name "file.ext" -exec dirname {} \; 
8

usted no tiene que llamar dirname() para cada archivo encontrado. con GNU encontrar, puede utilizar -printf y su rápido de esta manera

find /path -type f -iname "*.ext" -printf "%h\n" 
17

Así que el problema es que $ (...) o `...` comienza un nuevo shell antes de hacer la sustitución.

considerar el uso -C bash:

$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \; 

Eso cambia el nombre de cualquier icono en un repositorio git a una forma más estándar.

Aquí {} se reemplaza antes de ejecutar cualquier cosa, por lo que el problema se ha ido.

Para ese ejemplo, TMTOWTDI, pero trato de mantenerlo simple para que pueda comenzar lo que realmente necesita hacer.

2

Muestra los puntos, porque la sustitución del proceso se evalúa antes de que se ejecute realmente el comando. Entonces debes pasar tu comando a una instancia de shell separada.

En cuanto a la solución, utilice la siguiente sintaxis:

find $PWD -name "file.ext" -exec sh -c 'echo $(dirname {})' ';' 

Sin embargo, la forma más fácil de imprimir o ejecutar algo en cada directorio es por -execdir, por ejemplo:

find . -name "file.ext" -execdir pwd ';' 
+0

¡Esta es la única respuesta que funciona para mí! – Leonmax

Cuestiones relacionadas