Excluir diretórios na pesquisa por localização

12

Uma pesquisa com locate encontra caminhos no sistema de arquivos.
Muitas vezes, você sabe a priori que você está interessado apenas em arquivos ou diretórios.
Uma pesquisa 'localizar' geralmente retorna muitos resultados. Seria útil incluir apenas um dos tipos no resultado, porque ajuda a encurtar a saída.

Mas há um argumento mais interessante para deixar de fora arquivos ou diretórios: porque a lista de caminhos de resultados pode ser ambígua - não apenas na teoria.

O exemplo abaixo é um caso do mundo real e não incomum:

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

Ok, encontramos algo! Mas ... arquivos ou diretórios?

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

Então, esse é um arquivo ...

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

enquanto o segundo não é.

Esta ambiguidade está dificultando a leitura de longas listas de caminhos, por isso seria muito bom filtrar diretórios, por exemplo, usando uma opção de linha de comman para locate .

Existe algo assim? Mesmo que o filtro para diretórios seja separado do local?

Pelo menos, pode-se usar um script para iterar todos os nomes de arquivos a serem verificados - o que pode ser lento.

    
por Volker Siegel 26.03.2015 / 20:48

6 respostas

3

com zsh :

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

(0) é um sinalizador de expansão de parâmetro que divide em caracteres NUL (como usamos locate -0 ), abreviação de (ps:^:) .

Com (N.) , em vez de adicionar (N.) no final da matriz, nós o adicionamos a cada elemento.

. é um qualificador de glob, N para corresponder apenas a arquivos regulares, ^/ para remover o elemento se ele não corresponder (não existe ou não é um arquivo comum ou não podemos Verifica). Você também pode usar . em vez de print -rl para corresponder a não-diretórios, em vez de apenas arquivos regulares.

zsh imprime cada argumento raw em uma linha separada .

Você pode usar qualquer qualificador locate glob, mas note que os pedidos não terão nenhum efeito, já que estamos expandindo um glob por arquivo aqui, então há apenas um arquivo para classificar para cada um.

(note que pode falhar se o último arquivo relatado por %code% terminar em caracteres de nova linha (um erro de substituição de comando presente em todos os shells)).

    
por 27.03.2015 / 13:16
3

Isso é tão deselegante quanto as outras respostas, mas talvez menos ineficiente:

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

(dividido em duas linhas para facilitar a leitura). O acima irá lidar com nomes contendo espaços. O IFS= parece ser necessário para lidar com nomes com espaços à direita , e, claro, o -r permite lidar com barras invertidas.

A abordagem "vamos canalizar locate para algo" pode estar fadada ao fracasso se nomes de caminho contendo novas linhas estiverem presentes.

Para mais informações sobre IFS , leia sh(1) ou bash(1) (digitando man sh ou man bash em um sistema * nix, e / ou lê-lo aqui , aqui , aqui , e / ou aqui ). Em seguida, leia Entendendo o IFS e Bash: leia linha por linha, com o IFS no Stack Exchange (concentre-se nas respostas com mais de 5 votos), e, se você ainda não tiver o suficiente, confira IFS no Greg's Wiki e Resultados de pesquisa do IFS no Wiki do Bash Hackers (não no Stack Exchange).

    
por 26.03.2015 / 22:43
2
locate --null --regex --basename "xfce4-keyboard-overlay$" |
  xargs -r0 sh -c 'find "$@" -prune ! -type d' sh
    
por 26.03.2015 / 21:34
1

xargs irá repetir o comando para cada linha se você especificar o parâmetro -L 1 ou -i .

Veja aqui

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

Evidentemente, é o kick de um novo shell para cada arquivo, mas tem a vantagem de ser bom e compacto.

EDIT: Eu não estava muito feliz com essa resposta porque estava chutando um novo shell para cada arquivo. Isso deve ter apenas dois processos:

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

É claro que seria bom evitar o chute de um interpretador, mas xargs parece estar paralisado em sua capacidade de encadear comandos.

    
por 27.03.2015 / 10:31
0

Meus dois centavos:

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

Isto é mais ou menos como o G-Man combinou com a substituição de processos.

    
por 26.03.2015 / 23:46
-1

E se você combinar locate com file e grep ? ...

$ for f in 'locate --regex --basename "xfce4-keyboard-overlay$"'; do file $f; done | grep -vi directory
    
por 26.03.2015 / 22:04