Eu tenho um conjunto de txt
arquivos cujos nomes podem conter espaços ou caracteres especiais como #
.
Eu tenho uma grep
solução grep -L "cannot have" $(grep -l "must have" *.txt)
para listar todos os arquivos que possuem, must have
mas não cannot have
.
Por exemplo, existe um arquivo abc defg.txt
que contém apenas 1 linha: must have
.
Normalmente, a solução grep deve descobrir abc defg.txt
, mas retorna:
grep: abc: No such file or directory
grep: defg.txt: No such file or directory
Acho que para nomes de arquivos que contêm #
, a solução grep também é inválida.
Alguém poderia me ajudar a alterar a solução grep?
Responder1
SEvocê está disposto a ir mais longe, o awk pode fazer isso de uma só vez:
awk 'function s(){if(a&&!b){print f}} FNR==1{s();f=FILENAME;a=b=0}
/must have/{a=1} /cannot have/{b=1} END{s()}' filepattern
Para ficar mais atualizado, você pode simplificar com BEGINFILE e ENDFILE. (Como todas as respostas do awk, você pode colocar os comandos do awk em um arquivo com -f e, como a maioria, pode converter facilmente para perl, se preferir.)
Responder2
Como você já está usando opções específicas do GNU ( -L
), você poderia fazer:
grep -lZ -- "must have" *.txt | xargs -r0 grep -L -- "cannot have"
A ideia é usar -Z
para imprimir a lista de nomes de arquivos delimitados por NUL e usar xargs -r0
para passar essa lista como argumentos para o segundo arquivo grep
.
A substituição de comando, por padrão, divide-se em espaço, tabulação e nova linha (e NUL em zsh
). Conchas semelhantes a Bourne, além de zsh
também realizarem globbing em cada palavra resultante dessa divisão.
Você poderia fazer:
IFS='
' # split on newline only
set -f # disable globbing
grep -L -- "cannot have" $(
set +f # we need globbing for *.txt in this subshell though
grep -l -- "must have" *.txt
)
Mas isso ainda seria interrompido em nomes de arquivos contendo caracteres de nova linha.
Em zsh
(e zsh
somente), você pode fazer:
IFS=$'\0'
grep -L -- "cannot have" $(grep -lZ -- "must have" *.txt)
Ou:
grep -L -- "cannot have" ${(ps:\0:)"$(grep -lZ -- "must have" *.txt)"}
Responder3
Considere find
usar grep
um comando shell:
find . -name '*.txt' -print0 | xargs -0 -I{} sh -c 'grep -q "must have" -- "{}" && grep -L "cannot have" -- "{}"'