resumo:
- Um determinado sistema tem muitos arquivos de texto com nomes
~=
[type of file].[8-digit date]
. - Para pesquisar esses arquivos, eu gosto (e quero manter) usando este idioma:
find /path/ -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'
(ondennnn
== ano de 4 dígitos) - ... e na última década também fiz
find
glob ao longo de anos comofind /path/ -name 'file.201[89]*' -print | xargs ...
- ... mas agora não posso fazer
find
glob em 2019 e 2020 comfind /path/ -name 'file.20{19,20}*' -print | xargs ...
- ... embora esse "globbing de chaves" (termo correto?) funcione bem com
ls
!
Existe uma maneira {concisa, elegante} de dizer find
o que eu quero, sem fazer a pós- find
limpeza (ou seja, o que estou fazendo agora) à la
find /path/ -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...
? FWIW, prefiro uma solução que funcione com xargs
.
detalhes:
Trabalho em um sistema com muitas convenções que me precedem há muito tempo e que não posso mudar. Uma delas é que tem muitos arquivos de texto com nomes ~=
[type of file].[8-digit date]
, por exemplo, woohoo_log.20191230
. Ao pesquisar nesses arquivos por algum texto, normalmente (como em, quase sempre) uso o find ... grep
idioma (geralmente usando Emacs' M-x find-grep
). (FWIW, este é um sistema Linux com
$ find --version
find (GNU findutils) 4.4.2
...
$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
e atualmente não tenho status para alterar qualquer um deles, se eu quisesse.) Muitas vezes, conheço o intervalo de anos do assunto em questão e, portanto, tentarei restringir o que find
retorna (para acelerar o processamento), com (por exemplo)
find /path/ -type f -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'
onde nnnn
== ano de 4 dígitos. Este WFM, e eu gosto (e quero continuar) usando o idioma acima ... especialmente porque também posso usá-lo para pesquisar anos como
find /path/ -type f -name 'file.201[89]*' -print | xargs ...
Mas esta nova década parece estar quebrando esse idioma, e (para mim pelo menos) de forma mais estranha. (Eu não estava aqui quando a última década mudou.) Suponha que eu escolha um texto que sei que está em um arquivo de 2019 && um arquivo de 2020 (como em, posso abrir os arquivos e ver o texto). Se eu atualmente faço
find /path/ -name 'file.20{19,20}*' -print | xargs ...
grep
termina inesperadamente/irritantemente with no matches found
, porque
$ find /path/ -name 'file.20{19,20}*' -print | wc -l
0
Mas se eu fizer
find /path/ -type f -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...
grep
retorna os resultados esperados. O que é bom, mas ... ummm ... isso é apenas feio, especialmente desde que este "glob de chaves" (por favor, corrija-me se este uso estiver incorreto ou obsoleto) funciona a partir de ls
! Ou seja, isso me mostra os arquivos no intervalo de ano relevante (ou seja, 2019..2020)
ls -al /path/file.20{19,20}*
Por isso gostaria de saber:
- Não estou dando
find
o glob certo para este caso de uso? O que eu preciso dizerfind
para fazê-lo fazer o quels
está fazendo corretamente/capazmente? - Isso é um problema com
xargs
? Se sim, posso viver com umafind ... -exec
solução, mas... meu cérebro funciona melhor comxargs
o , então prefiro ficar com isso se possível. (Me chame de débil mental, mas-exec
a sintaxe de faz meu cérebro doer .)
Com
zsh
, você pode usar globbing recursivo e seu<x-y>
operador glob que corresponde a intervalos de números decimais:(o
(D)
para também procurar em diretórios ocultos (D
ot) comofind
faria; presumivelmente você pode omiti-los se não os quiser, e-.
é restringir ao arquivo regular (.
) identificado após a resolução do link simbólico (-
)).Observe que também corresponderia
file.00002020
(já que é um número decimal entre 2019 e 2020) e, como em sua abordagem,file.20201234
comofile.2020
quais correspondênciasfile.<2019-2020>
seguidas por1234
quais correspondências*
.A maneira padrão (POSIX
sh
e utilitários) de fazer isso seria com:(onde adicionar
/dev/null
você obtém o mesmo efeito que GNUgrep
para-H
forçar o nome do arquivo a ser exibido)Observe que a saída de
find -print
não é compatível com o formato de entrada esperado dexargs
. Com os utilitários GNU, você pode usarfind -print0
exargs -r0
, mas isso não é necessário, poisfind -exec ... {} +
tem o mesmo comportamento, é mais curto e mais portátil.Em
ls -al /path/file.20{19,20}*
, não é issols
que faz nada com{19,20}*
. Nesse comando, o shell executa expansão de chaves e globbing ,/path/file.20{19,20}*
pois não é citado :Em
find /path/ -name 'file.20{19,20}*'
,'file.20{19,20}*'
é citado, então o shell o deixa em paz e,find
em seguida, aplica suas próprias regras de correspondência de padrões , que não suportam expansão de chaves. Aqui citando o manual GNUfind
:Se você realmente deseja usar a expansão de chaves para pesquisar recursivamente um diretório, no bash, você pode habilitar o globbing recursivo (
globstar
) (e possivelmentedotglob
procurar no diretório oculto comofind
faria) e usarprintf
comxargs
:Ou você pode usar
find
com-regex
em vez de-name
como suportado por algumasfind
implementações. Com GNUfind
:Não é uma resposta geral para sua pergunta, mas pode haver uma maneira fácil de fazer isso, dependendo da quantidade de histórico de arquivos que você possui. Muitas vezes me deparei com uma situação semelhante com meses ao procurar coisas em setembro / outubro. Uma solução fácil é usar o padrão a como este:
Não é idêntico, porque, além de 2019 e 2020, também corresponderá a 2010 e 2029. Presumivelmente, você ainda não tem nenhum arquivo datado de 2029. Se seu arquivo não remonta a 2010, isso deve ser funcionalmente equivalente.