É 'grep -v -l' equivalente a 'grep -L'?

6

De vez em quando, há uma resposta (ou um comentário) que sugere o uso das opções grep -v e -l em vez do -L (especialmente quando o último não está disponível). Os autores parecem acreditar que são equivalentes.

Então, eles são intercambiáveis? IOW, grep -v -l produz o mesmo resultado que grep -L ?

    
por don_crissti 23.01.2017 / 20:24

2 respostas

10

Não, eles não são equivalentes e, como tal, os resultados quase sempre 1 serão diferentes.
Vamos ver o que cada um desses switches faz:

‘-L’
‘--files-without-match’
     Suppress normal output; instead print the name of each input file
     from which no output would normally have been printed.

Isso deve ser simples:
grep -L 'pattern' ./*
imprime o nome de cada arquivo que não contém nenhuma linha correspondente a 'pattern' .

‘-v’
‘--invert-match’
     Invert the sense of matching, to select non-matching lines.

Isso também deve ser muito simples:
grep -v 'pattern' ./*
imprime todas as linhas que não correspondem a 'pattern' de cada arquivo.

‘-l’
‘--files-with-matches’
     Suppress normal output; instead print the name of each input file
     from which output would normally have been printed.

Novamente, simples:
grep -l 'pattern' ./*
imprime o nome de cada arquivo que contém pelo menos uma linha correspondente a 'pattern' .

Agora, o que acontece quando combinamos -v e -l ? Não é muito diferente de grep -l , exceto que ele seleciona as linhas não correspondentes, portanto, grep -vl 'pattern' ./*
imprime o nome de cada arquivo que contém pelo menos uma linha que não corresponde a 'pattern' .

Então, observe a diferença:

grep -L imprime o nome do arquivo somente se não houver correspondência de linha 'pattern'
grep -vl imprime o nome do arquivo somente se houver pelo menos uma linha não correspondente 'pattern'

1:
Com base no acima, é fácil ver quando esses dois comandos poderiam produzir a mesma saída: - quando o arquivo não está vazio e todas as linhas correspondem ao padrão - nesse caso, não haverá saída. -ou quando o arquivo não está vazio e a linha no corresponde ao padrão - caso em que ele será listado

Moral da história: nunca use grep -vl para emular grep -L .
Se o seu grep não suportar -L , esta é a maneira correta de imitá-lo .

    
por 23.01.2017 / 20:25
3

Como nota extra, em sistemas cuja grep não suporta a opção -L (uma extensão GNU), o uso de -vl não ajudaria, já que @don_crissti mostrou que você precisaria recorrer a um loop de shell. O equivalente de

grep -L pattern ./*

seria:

for file in ./*; do
  {
     grep -q pattern || printf '%s\n' "$file"
  } < "$file"
done

Você notará que o redirecionamento é feito em todo o {...} em vez de apenas grep , pois não queremos que o nome do arquivo seja impresso se não puder ser aberto.

Para o equivalente a grep -ZL pattern ./* (que você precisa para poder pós-processar a saída de forma confiável), substitua %s\n por %sgrep -rL pattern . acima.

Para o equivalente do -readable do GNU, você pode fazer:

find . -type f ! -exec grep -q pattern {} \; -print

Embora também imprima os nomes dos arquivos que não são legíveis (o predicado find grep pode ser usado, mas também é uma extensão GNU, então é provável que o seu -L não suporte find , seu -readable não suportará zsh ).

com %code% :

for f (./**/*(DN.:) {{grep -q pattern || print -r $f}<$f}
    
por 24.01.2017 / 14:14

Tags