Encontre todos os PDFs com pelo menos três caracteres em seus nomes

9

Gostaria de encontrar os arquivos PDF cujo nome (excluindo a extensão) seja maior que três.

$ find ~ -iregex ".{3,}/.pdf"

não retorna nada, mas

$ find ~ -iregex ".+/.pdf"

funciona.

Como posso ativar a variante {3,} ?

    
por JawSaw 11.05.2018 / 13:25

3 respostas

18

Supondo que você esteja usando o GNU find (o que você provavelmente é, pois -iregex é uma extensão do GNU para POSIX find ), -regex e -iregex padrão para expressões regulares do Emacs, que não reconhecem {3,} . Você precisa especificar um tipo diferente de expressões regulares usando a opção -regextype ; Além disso, você precisa ajustar sua expressão regular ao fato de a expressão corresponder ao caminho completo:

find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'

Você também deve escapar do . para que corresponda a "." ao invés de qualquer caractere:

find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'

A expressão regular pode ser simplificada, pois só nos preocupamos com três caracteres não "/":

find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'

Para completar, com o FreeBSD ou o NetBSD find (outra implementação que suporta -iregex , não sua, já que .+ não funcionaria lá sem -E ), você escreveria:

find ~ -iregex '.*[^/]\{3\}\.pdf'

ou:

find -E ~ -iregex '.*[^/]{3}\.pdf'

Sem -E , isso é expressão regular básica (como em grep ) e com -E expressão regular estendida (como em grep -E ). / p>

Com find de ast-open:

find ~ -iregex '.*[^/]{3}\.pdf'

(isso é ampliado novamente para fora da caixa).

    
por 11.05.2018 / 13:40
20

Aqui é mais fácil com curingas padrão:

find ~ -name '*???.[pP][dD][fF]'

Ou com algumas implementações de find (as que suportam -regex também suportam -iname ):

find ~ -iname '*???.pdf'

Para números arbitrários de caracteres em vez de 3 , é aí que você pode preferir reverter para -iregex quando disponível (veja resposta do @Stephen Kitt ) ou você pode usar zsh ou ksh93 globs:

  • zsh :

    set -o extendedglob # best in ~/.zshrc
    printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
    

    (o (D) considera arquivos e arquivos ocultos em diretórios ocultos como find )

    • (#cx,y) é o% curinga equivalente a regexp zsh
    • {x,y} para maiúsculas e minúsculas
    • % curinga padrão(#i) para qualquer caractere único (como regexp ? )
    • . : qualquer nível de subdiretórios (incluindo 0)
  • **/ :

    FIGNORE='@(.|..)' # to consider hidden files
    set -o globstar
    printf '%s\n' **/{3,}(?).~(i:pdf)
    
    • ksh93 : operador estendido de curinga do ksh semelhante a regexp @(x|y) .
    • (x|y) : variável especial que controla quais arquivos são ignorados por globs. Quando definido, a ignorância usual de arquivos ocultos não é feita, mas ainda queremos ignorar as entradas do diretório FIGNORE e . onde presentes.
    • .. é equivalente a {x,y}(z) de regexp ksh93 .
    • z{x,y} : correspondência insensível a maiúsculas e minúsculas.

As globs têm algumas vantagens extras sobre ~(i:...) aqui, pois você obtém uma lista classificada (é possível desativar essa classificação em find com o qualificador zsh glob ou usar critérios de classificação diferentes) e também funcionar quando nomes de arquivo contêm seqüência de bytes que não formam caracteres válidos (por exemplo, em uma localidade usando o conjunto de caracteres UTF-8, a abordagem oN falharia ao reportar um find , pois $'St\xE9phane Chazelas - CV.pdf não sendo um caractere não é correspondido por regexp \xE9 ou curinga . ou ? com GNU * ).

    
por 11.05.2018 / 13:58
7

Como sei que são PDFs?

Você não a menos que você pergunte. Claro, estou sendo pedante, mas você não perguntou sobre arquivos com .pdf em seus nomes . Só porque um arquivo tem os caracteres .pdf no nome do arquivo não faz dele um arquivo PDF .

Na verdade, vamos ser todo o caminho pedante sobre isso: se os últimos quatro caracteres do nome de um arquivo forem .pdf , então ele sempre terá mais de três caracteres em seu nome .

Então, fazendo isso do jeito errado , você pode dizer:

$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf

Veja esse segundo? Na verdade, é um executável. (Eu sei, eu mudei o nome.) E eu também estou sentindo falta de um PDF que eu poderia jurar estava no diretório Documentos ...

$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf

Então, usando -iname , poderíamos encontrar esse, mas ainda está criando esse arquivo não-PDF.

O que nós realmente queremos fazer neste caso é examinar o número mágico do arquivo usando o comando file . Uma opção gera o tipo MIME , que é mais simples de analisar. A consulta find se torna um simples -name "???*" .

$ find . -type f -name "???*" -print0|xargs -0 file --mime
./.bash_history:                                              text/plain; charset=us-ascii
./.bash_logout:                                               text/plain; charset=us-ascii
./.bashrc:                                                    text/plain; charset=us-ascii
./.profile:                                                   text/plain; charset=us-ascii
./Documents/McLaren 720s Coupe:Order Summary.pdf:             application/pdf; charset=binary
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF: application/pdf; charset=binary
./Documents/Setup_MagicISO.exe.pdf:                           application/x-dosexec; charset=binary
./Downloads/Setup_MagicISO.exe:                               application/x-dosexec; charset=binary
./Downloads/WindowsUpdate.diagcab:                            application/vnd.ms-cab-compressed; charset=binary

Vamos usar o delimitador de dois pontos e procurar o tipo MIME application/pdf , depois zerar essa parte e imprimir o resultado. Tome nota, um dos meus arquivos tem dois pontos no nome; então eu não posso simplesmente pedir ao awk para ($2==":"){print $1} .

$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF

Agora vamos terminar inventando arquivos PDF com o nome a e abc :

$ mkdir Documents/other
$ cp -a Documents/McLaren\ 720s\ Coupe\:Order\ Summary.pdf Documents/other/a
$ cp -a Documents/Pioneer\ Premier\ DEH-P490IB\ CD\ Install\ Manual.PDF  Documents/other/abc
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
./Documents/other/abc

Isso é tudo. Eu sei que provavelmente vou ser dinged por ser horrivelmente pedante, mas no meu trabalho com milhares de volumes NFS para caçar e todos os tipos de arquivos com nomes ruins, eu desejo que mais pessoas sejam pedantes.

Editado para adicionar: no mundo real, talvez eu queira usar updatedb para criar um índice de arquivo pesquisável, locate em vez de find ler esse índice e parallel em vez de xargs para encadear. Isso está um pouco fora do escopo desta questão. Eu escrevi isso com uma cara séria também. Por que eu me importo tanto? Eu poderia estar procurando por arquivos de filme e áudio; ou certos tipos de fotografias; ou executáveis binários em um diretório de dados do projeto.

    
por 11.05.2018 / 22:21

Tags