É possível tornar o uso mais eficiente do que o Find + Grep neste cenário?

6

Eu sempre me vejo procurando por um arquivo na pasta atual e em subpastas com base em parte do nome dele. Parece-me que, neste caso, find + grep requer menos digitação do que apenas find . Por exemplo.

find . | grep user   #19 chars typed

tem que ser escrito apenas com o seguinte:

find . -path "user*" #21 chars typed

Parece meio bobo digitar mais caracteres ao usar um único comando que foi feito para encontrar arquivos ... e depois usar dois deles em combinação.

Existe alguma maneira de fazer com que o uso seja apenas mais eficiente em termos de caracteres digitados?

    
por mircealungu 05.03.2018 / 13:20

5 respostas

11

Sim,

ff () {
    find . -path "*$1*"
}

Esta função é invocada como

ff user

e retornará todos os nomes de caminho (de arquivos, diretórios, etc.) dentro ou abaixo do diretório atual que contém a string fornecida.

A definição da função deve ir para o seu arquivo ~/.bashrc (ou o arquivo de inicialização do shell correspondente que é usado pelo seu shell) e será utilizável no próximo shell interativo que você iniciar.

A seguinte variação considera apenas a parte do nome do caminho do nome do caminho:

ff () {
    find . -name "*$1*"
}

Se você também quiser restringir os resultados a apenas arquivos regulares , adicione -type f à invocação find :

ff () {
    find . -type f -name "*$1*"
}

Observe que seu comando

find . -path "user*"

nunca produzirá nada. Isso ocorre porque todo nome de caminho considerado começará com . .

E, finalmente, uma palavra de cautela: Estou assumindo que isso será usado de forma interativa e que você usará seus olhos para procurar o resultado. Se você planeja usá-lo em um script ou para fazer qualquer loop sobre nomes de arquivos retornados pela função, consulte " Por que o loop está sendo executado sobre a má prática de saída? ".

    
por 05.03.2018 / 13:25
6

Supondo que você queira fazer alguma coisa com esses arquivos posteriormente, você pode permitir que o seu sistema de completação de shell mostre essa lista e selecione entradas para eles.

Por exemplo, com zsh :

$ echo **/*user*Tab
Completing expansions
[4/user]      1/2/3/user
Completing all expansions
1/2/3/user 4/user
Completing original
**/*user*

Em seguida, use as teclas de seta para selecionar qual arquivo (ou arquivos com Alt + A ) você deseja selecionar (mostrado em vídeo reverso, indicado acima com [...] ). Veja também Ctrl + D para listar apenas as conclusões sem começar a selecionar nenhuma.

Aqui com seu ~/.zshrc contendo pelo menos:

zstyle ':completion:*' completer _expand _complete
zstyle ':completion:*' menu select=0
zstyle ':completion:*' verbose true
zstyle ':completion:*' format 'Completing %d'
zstyle ':completion:*' group-name ''
autoload -Uz compinit
compinit

Sugiro que você execute compinstall para ajustar suas preferências de conclusão.

Acima de, **/*user* retorna os arquivos cujo nome contém user (excluindo os ocultos e arquivos em diretórios ocultos, adicione o qualificador (D) glob, se desejar que eles sejam recuperados). Para arquivos cujo caminho contenha user , mude para **/*~^*user* (precisa de set -o extendedglob no seu ~/.zshrc ).

Isso também tem o benefício de fornecer uma lista classificada, e você pode obter a lista colorida (à la GNU ls --colour ) além do / , @ suficiente para ajudá-lo a identificar os tipos de arquivos se você adicionar:

eval "$(dircolors ~/.dircolors)"
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}

Para o seu ~/.zshrc .

Ele também evitará problemas com nomes de arquivos com caracteres de nova linha ou outros caracteres não imprimíveis, já que a saída de conclusão, em oposição à saída de find , é destinada ao consumo humano.

zsh também não possui find (pelo menos GNU find 's) sobre nomes de arquivos contendo sequências de bytes que não formam caracteres válidos (onde find -path '*user*' não conseguiria encontrar user file em um diretório $'St\xe9phane' quando em uma localidade UTF-8, por exemplo).

    
por 05.03.2018 / 13:42
2

A versão GNU de find é padronizada para o diretório atual se nenhum caminho estiver definido.

find -name "user*" # 18 chars typed plus enter.

    
por 05.03.2018 / 13:55
2

find . | grep user e find . -path "user*" fazem duas coisas bem diferentes. Eles podem parecer que são iguais, mas não são.

Vou mencionar as duas diferenças mais óbvias primeiro apenas para tirá-las do caminho. A primeira é que você precisa usar -path '*user*' para obter exatamente o mesmo resultado que o grep user . Isso não é muito importante. A segunda diferença óbvia, um pouco mais importante, é que a execução de dois processos, quando um é feito, é inerentemente menos eficiente (em termos de uso de CPU e RAM) - uma eficiência mais significativa do que salvar dois pressionamentos de teclas.

A verdadeira diferença, no entanto, é o que você pode fazer facilmente com os nomes de arquivos encontrados pelo find em si, e aqueles encontrados usando grep . Como a maioria dos utilitários de linha de comando no linux / unix, o find é uma ferramenta muito flexível - ele é capaz de muito mais do que apenas localizar arquivos e imprimir seus nomes de arquivos.

Com o pipe para grep, você tem apenas uma lista de nomes de arquivos que correspondem a um padrão específico.

Se você usou o caractere A NUL como separador de nome de arquivo, em vez de apenas uma nova linha (wg com -print0 action e% GNU grep -z aka --null-data ), é possível canalizá-lo com segurança em xargs -0 (ou perl ou awk ou qualquer outro programa que possa receber entrada separada por NUL) e processar os arquivos.

por exemplo. usando du -sch como um exemplo muito simples:

find . -print0 | grep -z user | xargs -0r du -sch --

Se você não fez isso, ou se a sua versão de grep não suporta -z , então você só pode processar seus nomes de arquivos com segurança se a) usar uma nova linha como separador de nome de arquivo eb) estiver absolutamente certeza de que nenhum dos nomes de arquivo conterá uma nova linha (novas linhas são válidas em nomes de arquivos - irritantes, mas verdadeiras, e algo com o que você ocasionalmente tem que lidar).

find . | grep user | xargs -d '\n' -r du -sch --

Ambos usam 4 processos (find, grep, xargs e du) em um pipeline para o uso total do disco dos nomes de arquivos.

Com find , no entanto, você pode usar as opções -exec ou -execdir para processar diretamente o nome do arquivo sem precisar se preocupar com o delimitador que está usando.

por exemplo,

find . -path '*user*' -exec du -sch -- {} +

Isso usa 2 processos (find e du) para obter o mesmo resultado.

A segunda diferença real (e essa é grande) é que, enquanto grep só pode selecionar arquivos combinando um padrão regex com o nome de cada arquivo, find pode usar os metadados de cada arquivo para filtrar correspondências indesejadas (ou para selecionar apenas correspondências muito específicas - mesma coisa)

Alguns exemplos de quais find são capazes de:

Se você quiser apenas arquivos regulares, use -type f , se quiser apenas diretórios, use -type d , symlinks -type l e assim por diante.

Se você deseja apenas arquivos pertencentes a um usuário específico, use -uid nnn ou -user username . mesmo para -gid nnn e -group groupname .

find pode corresponder a permissões, timestamps, tamanho e se um arquivo é -readable ou -writable pelo usuário que o executa.

Ele também incorporou a correspondência de expressão regular ( -regex , com a opção de estilos de regex usando -regextype ), bem como a correspondência de glob ( -name , -path ).

Você pode usar -prune para excluir árvores inteiras de subdiretórios da pesquisa (reduzindo a quantidade de i / o do disco e o tempo necessário).

Ele pode combinar tudo isso com operadores de lógica booleana AND, OR e NOT.

find também possui várias ações incorporadas. O padrão é -print e já mencionei -print0 . Ele também pode exibir qualquer um dos metadados disponíveis de um arquivo no formato que você quiser com sua ação -printf . Ele pode excluir arquivos com -delete ou exibir uma lista detalhada (semelhante a ls -l ) com -ls .

-exec executa qualquer processo externo e fornece a lista de arquivos correspondentes na linha de comando com {} . Um arquivo por vez, se você terminar o comando -exec com \; ou quantos couberem em uma linha de comando do shell por vez com + .

-execdir faz o mesmo, mas, se estiver usando \; , muda para o diretório de cada arquivo antes de executar o processo externo. Com + , ele é alterado para o diretório e, em seguida, executa o comando externo com tantos argumentos de nome de arquivo que caberão em uma linha de comando.

BTW, alguns dos predicados e ações predicados acima são extensões GNU, e podem não funcionar em outras versões não-GNU de find .

    
por 05.03.2018 / 16:04
0

Se você usar, uma vez, o comando pip install grin , você ganhará o grin & grind utilitários, (python 2 somente no momento eu tenho medo).

Usando o grind, sua consulta se torna:

grind user*

com 11 caracteres.

É claro que, se você estiver seguindo o caminho python, sempre poderá ter em seu caminho um arquivo chamado floc que é feito sob medida para fazer o tipo de pesquisa que você faz com mais frequência:

#!/usr/bin/env python3
from glob import glob
import sys
for arg in sys.argv[1:]:
   print('\n'.join(glob('**/{}*'.format(arg), recursive=True)))

Então, chmod +x floc para torná-lo executável. Sua consulta então se torna:

floc user

Com até 9 caracteres. É claro que você também pode criar um alias de shell para o comando original para obter uma redução semelhante.

    
por 09.03.2018 / 20:07

Tags