Escludere le directory nella ricerca individuare


12

Una ricerca con locatetrova i percorsi nel filesystem.
Spesso sai a priori di essere interessato solo ai file o solo alle directory.
Una ricerca 'individuare' spesso restituisce molti risultati. Sarebbe utile includere solo uno dei tipi nel risultato, perché aiuta a ridurre l'output.

Ma c'è un argomento più interessante da tralasciare file o directory: perché l'elenco dei percorsi dei risultati può essere ambiguo, non solo in teoria.

L'esempio che segue è un caso reale e non insolito:

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

Ok, abbiamo trovato qualcosa! Ma ... file o directory?

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

Quindi questo è un file ...

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

mentre il secondo no.

Questa ambiguità sta rendendo difficile la lettura di lunghi elenchi di percorsi, quindi sarebbe davvero bello filtrare le directory, ad esempio usando un'opzione di linea comune per locate.

Esiste qualcosa del genere? Anche se il filtro per le directory è separato da Locate?

Almeno, si potrebbe usare uno script per ripetere tutti i nomi dei file da controllare, il che potrebbe essere lento.

Risposte:


3

Con zsh:

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

(0)è un flag di espansione dei parametri che si divide su caratteri NUL (come usiamo locate -0), abbreviazione di (ps:\0:).

Con ^, invece di aggiungere (N.)alla fine dell'array, lo aggiungiamo a ciascun elemento.

(N.)è un qualificatore glob, .per abbinare solo i file normali, Nper rimuovere l'elemento se non corrisponde (non esiste o non è un file normale o non possiamo verificare). Puoi anche usare ^/invece di .abbinare non-directory invece che solo file normali.

print -rlstampa ogni argomento crudo su una riga separata .

Puoi utilizzare qualsiasi zshqualificatore di glob, ma nota che quelli di ordinazione non avranno alcun effetto, dal momento che stiamo espandendo un glob per file qui, quindi c'è solo un file da ordinare per ciascuno.

(si noti che potrebbe non riuscire se l'ultimo file segnalato locatetermina con caratteri di nuova riga (una funzionalità errata di sostituzione comando presente in tutte le shell)).


3

Questo è inelegante come le altre risposte, ma forse meno inefficiente:

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

(suddiviso in due righe per leggibilità). Quanto sopra gestirà i nomi contenenti spazi. L' IFS=sembra essere necessaria per gestire i nomi con finali spazi, e, naturalmente, il -rconsente di gestire backslash.

L' locateapproccio del "mettiamoci dentro qualcosa" potrebbe essere destinato a fallire se sono presenti percorsi che contengono nuove linee.


Per ulteriori informazioni su IFS, leggere sh(1)o bash(1) (digitando man sho man bashin un sistema * nix e / o leggendolo qui , qui , qui e / o qui ). Quindi leggi Comprensione di IFS e Bash: leggi riga per riga, con IFS su Stack Exchange (concentrati sulle risposte con più di 5 voti) e, se non ne hai ancora abbastanza, dai un'occhiata a IFS sui risultati di ricerca Wiki e IFS di Greg sul Wiki di Bash Hackers (non su Stack Exchange).


puoi aggiungere alcune informazioni su cosa fa "IFS =" dopo la tua whiledichiarazione?
Robert


le barre rovesciate continueranno a rappresentare un problema con molte implementazioni dell'eco. È necessario utilizzare printfper dati arbitrari .
Stéphane Chazelas,

potrebbe esserci una soluzione al tuo problema di newline usando il parametro "--null" per locateaumentare il tuo readcome suggerito qui transnum.blogspot.ie/2008/11/…
robert

@ StéphaneChazelas: buon punto. Fisso.
G-Man dice "Ripristina Monica" il

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

In realtà, è ancora più sporco di quanto sembri ... ma una buona ispezione. Facciamo finta che sia pseudocodice, quindi è utile :)
Volker Siegel il

1
@Volker: sono d'accordo che è male: elencherà /usr/local/share/xfce4-keyboard-overlay e ogni sua sottodirectory , nel tuo esempio. L'aggiunta -maxdepth 0aiuta.
G-Man dice "Ripristina Monica" il

Va ancora meglio ...: D locate --regex --basename "xfce4-keyboard-overlay$" | xargs -I % sh -c "test -d % && echo %"
FloHimself

1
L'utilizzo xargscon è findstata una buona idea, l'ho modificato per renderlo robusto. Spero non ti dispiaccia.
Stéphane Chazelas,

1

xargsripeterà il comando per ogni riga se si specifica -L 1o -iparametro.

Vedere qui

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

Certo, sta dando il via a una nuova shell per ogni file, ma ha il vantaggio di essere bella e compatta.

EDIT: Non ero abbastanza contento di quella risposta perché stava dando il calcio di una nuova shell per ogni file. Questo dovrebbe avere solo due processi:

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

Naturalmente sarebbe bello se potessimo evitare di dare dei calci a un interprete del tutto, ma xargssembra essere ostacolato nella sua capacità di incatenare comandi.


3
Quello ha appena riavviato la mia macchina (c'era un file chiamato /home/evil/$(reboot)/xfce4-keyboard-overlaye l'ho eseguito stupidamente come root).
Stéphane Chazelas,

2
@ StéphaneChazelas +1 per il coraggio di eseguire "codez casuali dagli internet" come root;) (scnr)
Volker Siegel

0

I miei due centesimi:

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

Questo è più o meno il modo in cui G-Man lo ha combinato con la sostituzione del processo.


In realtà, questo è più o meno il modo in cui l' ho fatto, combinato con la sostituzione del processo, meno la capacità di gestire nomi di file contenenti barre rovesciate o spazi vuoti finali. Inoltre, si noti che il titolo della domanda dice "escludi directory" e questa risposta include solo directory.
G-Man dice "Ripristina Monica" il

Scusa. Errore mio. Corretto.
Tristan Storch,

-1

E se ti unissi locatea filee grep? ...

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

Non ho testato, ma penso che potrebbe essere lento, perché crea un processo fileper ogni singolo percorso. Si noti che spesso ci sono molte righe di risultati per individuare. Il mio attuale test è alla ricerca di "gnome", dando circa 73000 percorsi da testare.
Volker Siegel,

2
@Volker: È peggio di così: per ogni $ffile che è, il fileprogramma aprirà quel file e leggerà da esso . Questo è molto costoso quando tutto ciò che devi fare è a stat(). .... ... ... ... ... ... (Inoltre, la for f in `…`; do …sintassi non è in grado di gestire nomi contenenti spazi.)
G-Man dice "Reinstate Monica",
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.