Excluir directorios en la búsqueda de localización


12

Una búsqueda con locateencuentra rutas en el sistema de archivos.
A menudo, usted sabe a priori que está interesado en archivos o directorios solamente.
Una búsqueda 'localizar' a menudo devuelve muchos resultados. Sería útil incluir solo uno de los tipos en el resultado, ya que ayuda a acortar la salida.

Pero hay un argumento más interesante para omitir archivos o directorios: porque la lista de rutas de resultados puede ser ambigua, no solo en teoría.

El siguiente ejemplo es un caso del mundo real, y no es inusual:

$ locate --regex --basename "xfce4-keyboard-overlay$"
/usr/local/bin/xfce4-keyboard-overlay
/usr/local/share/xfce4-keyboard-overlay

Ok, encontramos algo! Pero ... ¿archivos o directorios?

$ file /usr/local/bin/xfce4-keyboard-overlay 
/usr/local/bin/xfce4-keyboard-overlay:   bash script

Entonces ese es un archivo ...

$ file /usr/local/share/xfce4-keyboard-overlay
/usr/local/share/xfce4-keyboard-overlay: directory

mientras que el segundo no lo es.

Esta ambigüedad está haciendo que las largas listas de rutas sean difíciles de leer, por lo que sería realmente bueno filtrar los directorios, por ejemplo, usando una opción de línea de comando para locate.

Existe algo como esto? ¿Incluso si el filtro para directorios está separado de localizar?

Al menos, uno podría usar un script para iterar todos los nombres de archivo para verificar, lo que puede ser lento.

Respuestas:


3

Con zsh:

print -rl ${(0)^"$(locate -0 ...)"}(N.)

(0)es un indicador de expansión de parámetros que se divide en caracteres NUL (como los usamos locate -0), abreviatura de (ps:\0:).

Con ^, en lugar de agregar (N.)al final de la matriz, lo agregamos a cada elemento.

(N.) es un calificador global . para que coincida solo con los archivos normales, Npara eliminar el elemento si no coincide (no existe o no es un archivo normal, o no podemos verificarlo). También puede usar en ^/lugar de .hacer coincidir los no directorios en lugar de solo los archivos normales.

print -rl imprime cada argumento procesar en una línea separada .

Puedes usar cualquier zsh calificador glob, pero tenga en cuenta que los que ordenan no tendrán ningún efecto, ya que estamos expandiendo un glob por archivo aquí, por lo que solo hay un archivo para ordenar por cada uno.

(tenga en cuenta que puede fallar si el último archivo informado por locatetermina en caracteres de nueva línea (una sustitución de comando está mal representada en todos los shells)).


3

Esto es tan poco elegante como las otras respuestas, pero tal vez menos ineficiente:

locate --regex --basename "xfce4-keyboard-overlay$" | 
        while IFS= read -r f; do [ -f "$f" ] && printf "%s\n" "$f"; done

(dividido en dos líneas para facilitar la lectura). Lo anterior manejará los nombres que contienen espacios. El IFS=parece ser necesario para manejar nombres con seguimiento espacios, y, por supuesto, el -rle permite manejar las barras invertidas.

El locateenfoque de "vamos a entrar en algo" puede estar condenado a fallar si hay nombres de ruta que contienen nuevas líneas.


Para obtener más información sobre IFS, lea sh(1)o bash(1) (escribiendo man sho man bashen un sistema * nix, y / o leyéndolo aquí , aquí , aquí y / o aquí ). Luego lea Entendiendo IFS y Bash: lea línea por línea, con IFS en Stack Exchange (enfóquese en las respuestas con más de 5 votos) y, si aún no ha tenido suficiente, consulte IFS en la Wiki de Greg y los resultados de búsqueda de IFS en Bash Hackers Wiki (no en Stack Exchange).


¿puede agregar alguna información sobre lo que hace el "IFS =" después de su whiledeclaración?
robert


las barras invertidas seguirán siendo un problema con muchas implementaciones de eco. Debe usar printfpara datos arbitrarios .
Stéphane Chazelas

puede haber una solución a su problema de líneas nuevas mediante el uso del parámetro "--null" locatey aumentar su readcomo se sugiere aquí transnum.blogspot.ie/2008/11/…
robert

@ StéphaneChazelas: Buen punto. Fijo.
G-Man dice 'Reincorporar a Monica' el

2
locate --null --regex --basename "xfce4-keyboard-overlay$" |
  xargs -r0 sh -c 'find "$@" -prune ! -type d' sh

En realidad, está aún más sucio de lo que parece ... pero es una buena inspiración. Supongamos que es pseudocódigo, entonces es útil :)
Volker Siegel

1
@Volker: Estoy de acuerdo en que es malo: enumerará /usr/local/share/xfce4-keyboard-overlay y todos sus subdirectorios , en su ejemplo. Agregar -maxdepth 0ayuda.
G-Man dice 'Restablece a Mónica' el

Va aún mejor ...: D locate --regex --basename "xfce4-keyboard-overlay$" | xargs -I % sh -c "test -d % && echo %"
Flo Él mismo

1
Usar xargscon findfue una buena idea, lo he editado para que sea robusto. Espero que no te importe.
Stéphane Chazelas

1

xargsrepetirá el comando para cada línea si especifica -L 1o -iparámetro.

Mira aquí

$ locate --regex --basename "xfce4-keyboard-overlay$" | xargs -i bash -c '(test -d "{}" && echo "{}")'

Es cierto que está pateando un nuevo shell para cada archivo, pero tiene la ventaja de ser agradable y compacto.

EDITAR: No estaba muy contento con esa respuesta porque estaba pateando un nuevo shell para cada archivo. Esto solo debe tener dos procesos:

$ locate --regex --basename "xfce4-keyboard-overlay$" | xargs -i echo 'test -d "{}" && echo "{}"' | bash

Por supuesto, sería bueno si pudiéramos evitar la patada de un intérprete por completo, pero xargsparece tener dificultades para encadenar comandos.


3
Ese solo reinició mi máquina (había un archivo llamado /home/evil/$(reboot)/xfce4-keyboard-overlayy lo ejecuté tontamente como root).
Stéphane Chazelas

2
@ StéphaneChazelas +1 por el coraje de ejecutar "codez aleatorio desde Internet" como root;) (scnr)
Volker Siegel

0

Mis dos centavos:

while IFS= read i; \
do \
  if [ -f "$i" ]; \
  then \
    echo "$i"; \
  fi; \
done < <(locate --regex --basename "xfce4-keyboard-overlay$")

Esta es más o menos la forma en que G-Man lo hizo combinado con la sustitución del proceso.


En realidad, esta es más o menos la forma en que lo hice, combinada con la sustitución de procesos, menos la capacidad de manejar nombres de archivos que contienen barras invertidas o tienen espacios en blanco al final. Además, tenga en cuenta que el título de la pregunta dice "excluir directorios", y esta respuesta incluye solo directorios.
G-Man dice 'Restablece a Mónica' el

Lo siento. Mi error. Corregido
Tristan Storch

-1

¿Qué pasa si combinas locatecon filey grep? ...

$ for f in `locate --regex --basename "xfce4-keyboard-overlay$"`; do file $f; done | grep -vi directory

No lo probé, pero creo que puede ser lento, porque crea un proceso filepara cada ruta. Tenga en cuenta que a menudo hay muchas líneas de resultados para localizar. Mi prueba actual está buscando "gnome", dando alrededor de 73000 rutas para probar.
Volker Siegel

2
@Volker: Es peor que eso: por cada $farchivo, el fileprograma abrirá ese archivo y leerá de él . Esto es extremadamente costoso cuando todo lo que necesita hacer es a stat(). ... ... ... ... Además, esto dará resultados incorrectos para los archivos que contienen "directorio" en sus nombres (como "directorio_de_teléfono"). ... ... ... ... ... (Además, la for f in `…`; do …sintaxis no puede manejar nombres que contengan espacios.)
G-hombre dice 'Restablecer Mónica'
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.