Suponha que um diretório tenha 100 arquivos começando com a letra 'a'.
Se eu fizer um a grep <some string> a*
partir do terminal, como o shell lidará com isso?
Ele expandirá a expressão regular, obterá uma lista de todos os arquivos começando com ae grep em cada um deles sequencialmente? Ou existe alguma outra maneira?
Suponha que eu tenho uma matriz dos nomes de arquivos acima que começam com 'a'. Levará mais / menos tempo se eu escrever um loop for e fizer a iteração em um shell script ou programa ac?
glob
expressão regular. Grande diferença.Respostas:
Primeiro, um nitpick: uma string como
a*
na sintaxe normal do shell é uma glob, que funciona de maneira diferente das expressões regulares.Em uma visão geral de alto nível, o interpretador de shell (ou seja, bash) expande a string
a*
para uma lista de todos os nomes de arquivos que correspondem ao padrãoa*
. Eles então se tornam parte dos parâmetros da linha de comando em uma única instância degrep
(para os programadores, todas as palavras expandidas passam como strings separadas para oargv
argumento demain
). Essegrep
comando único analisa os argumentos da maneira que escolher, e cabegrep
a interpretá-los como nomes de arquivo, opções, argumentos de opção, expressões regulares etc. e executar as ações apropriadas. Tudo ocorre sequencialmente (AFAIK nenhumagrep
implementação usa vários threads).Se você implementar um loop em um script de shell para fazer a mesma coisa, é quase garantido que será mais lento que o processo acima, pelos seguintes motivos. Se você gerar um novo processo grep para cada arquivo, certamente será mais lento devido ao aumento da sobrecarga da criação do processo desnecessariamente. Se você construiu a lista de argumentos no script do shell e usou uma única instância de
grep
, qualquer coisa que você faça no shell ainda será mais lenta porque os comandos do shell precisam ser interpretados (por bash), o que adiciona uma camada extra de código, e você basta reimplementar o que o bash já estava fazendo mais rápido internamente no código compilado.Quanto a escrever você mesmo em C, provavelmente é possível obter facilmente um desempenho comparável ao processo descrito no primeiro parágrafo, mas é improvável que você consiga obter um ganho de desempenho suficiente nas implementações grep / bash atuais para justificar o tempo gastos sem investigar otimizações de desempenho específicas da máquina ou sacrificar a portabilidade. Talvez você possa tentar criar uma versão arbitrariamente paralelamente agradável de
grep
, mas mesmo isso pode não ajudar, pois é mais provável que você esteja vinculado à E / S do que à CPU. A expansão de globos e grep já são "rápidos o suficiente" para a maioria dos propósitos "normais".fonte
zcat
ezgrep
; não há necessidade de descompactá-los um por umSim, ele será expandido para uma lista de arquivos e alimentará a lista resultante para o
grep
programa. Pelo menos é o queman bash
diz na subseção Expansão do nome do caminho .Há outra maneira de usar a expansão em casos simples, como você menciona: escreva
grep <some_string> a
e antes de pressionar*
, pressione ESC. Isso expandirá a lista de arquivos correspondentes diretamente na linha de comando, para que você possa verificar se a lista está OK antes de pressionar Enter.Quanto à segunda parte da sua pergunta, isso depende. Se você deseja escrever um loop for que execute grep em cada um dos arquivos por sua vez, seria definitivamente mais lento, porque o programa grep será executado não uma vez, mas uma vez por arquivo. No entanto, o que é importante ter em mente é que existe um certo limite no comprimento expandido dos argumentos da linha de comando que você pode usar, embora normalmente seja bastante alto. Para ver isso, você pode tentar
grep adasdsadf /usr/*/*/* >/dev/null
.fonte
ESC+*
não é exatamente o mesmo que permitir que o bash se expanda * porqueESC+*
inserirá arquivos de ponto (nomes que começam com a.
), enquanto a expansão de*
depende dadotglob
shopt
configuração. A sequência de teclas para expandir e inserir globs éC-x *
por padrão e mapeia para o comando readlineglob-expand-word
.a*
expansão, mas certamente é importante em um escopo mais amplo.zsh
nota: apenas pressionar a tecla tab nos parâmetros expansíveis (padrões glob, expansão de chaves, substituição de comandos, ...) os expandirá.C-x
atalho e ele não expande a lista de arquivos no meu sistema (usando o bash).C-x *
apenas faz globs que apenas fazem nomes de arquivos, masEsc *
na verdade fazem muito maisinsert-completions
, como em todas as conclusões possíveis. Isso significa que usarEsc *
uma linha de comando vazia irá inserir o nome de cada arquivo executável no seu$PATH
, por exemplo.