Quero procurar recursivamente todos os *.pdf
arquivos em um diretório ~/foo
cujo nome base corresponda ao nome do diretório pai do arquivo.
Por exemplo, suponha que a estrutura de diretórios tenha ~/foo
esta aparência
foo
├── dir1
│ ├── dir1.pdf
│ └── dir1.txt
├── dir2
│ ├── dir2.tex
│ └── spam
│ └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf
Executar meu comando desejado retornaria
~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf
Isso é possível usando find
ou algum outro utilitário principal? Presumo que isso é possível usando a -regex
opção para, find
mas não tenho certeza de como escrever o padrão correto.
Respostas:
Com o GNU
find
:-regextype egrep
use regex estilo egrep..*/
coincidir com diretórios dos principais pais.([^/]+)/
corresponde ao diretório pai em um grupo.\1\.pdf
usebackreference
para combinar o nome do arquivo como o diretório pai.atualizar
Um (eu mesmo) pode pensar que
.*
é ganancioso o suficiente, é desnecessário excluir/
da correspondência dos pais:O comando acima não funcionará bem, porque combina
./a/b/a/b.pdf
:.*/
fósforos./
(.+)/
fósforosa/b/
\1.pdf
fósforosa/b.pdf
fonte
find . -regex '.*/\([^/]*\)/\1\.pdf'
então funcionaria com o BSDfind
.A variante de loop tradicional de
find .. -exec sh -c ''
usar as construções de shell para corresponder ao nome da base e o caminho imediato acima seria o seguinte.Para detalhar as expansões de parâmetros individuais
file
contém o caminho completo do.pdf
arquivo retornado dofind
comando"${file##*/}"
contém apenas a parte após a última,/
ou seja, apenas o nome da base do arquivo"${file%/*}"
contém o caminho até a final,/
ou seja, exceto a parte do nome da base do resultado"${path##*/}"
contém a parte após a última/
dapath
variável, ou seja, o caminho imediato da pasta acima do nome da base do arquivo"${base%.*}"
contém a parte do nome da base com a.pdf
extensão removidaPortanto, se o nome da base sem extensão corresponder ao nome da pasta imediata acima, imprimimos o caminho.
fonte
O inverso da resposta do Inian , ou seja, procure por diretórios e veja se eles contêm um arquivo com um nome específico.
A seguir, imprime os nomes dos caminhos dos arquivos encontrados em relação ao diretório
foo
:${dirpath##*/}
será substituído pela parte do nome do arquivo do caminho do diretório e poderá ser substituído por$(basename "$dirpath")
.Para pessoas que gostam da sintaxe de curto-circuito:
O benefício de fazer dessa maneira é que você pode ter mais arquivos PDF do que diretórios. O número de testes envolvidos é reduzido se um restringir a consulta pelo número menor (o número de diretórios).
Por exemplo, se um único diretório contiver 100 arquivos PDF, isso tentaria detectar apenas um deles, em vez de testar os nomes de todos os 100 arquivos em relação ao diretório.
fonte
com
zsh
:Cuidado que, embora
**/
não siga os links simbólicos,*/
seguirá.fonte
Não foi especificado, mas aqui está uma solução sem expressões regulares, se alguém estiver interessado.
Podemos usar
find . -type f
apenas para obter arquivos, depois utilizardirname
ebasename
escrever o condicional. Os utilitários têm o seguinte comportamento:basename
retorna apenas o nome do arquivo após o último/
:dirname
fornece todo o caminho até a final/
:Portanto,
basename $(dirname $file)
fornece o diretório pai do arquivo.Solução
Combine o que foi dito acima para formar o condicional e
"$(basename $file)" = "$(basename $(dirname $file))".pdf
, em seguida, imprima cada resultado apenasfind
se esse condicional retornar verdadeiro.No exemplo acima, adicionamos um diretório / arquivo com espaços no nome para tratar desse caso (graças a @Kusalananda nos comentários)
fonte
Final Thesis.pdf
(com um espaço).Faço bash globbing, testes simples de loop sobre string em qualquer dia no programa Find . Me chame de irracional e, embora possa ser subótimo, esse código simples serve para mim: legível e reutilizável, satisfazendo até! Permitam-me, portanto, sugerir uma combinação de:
• festa globstar :
for f in ** ; do ...
** laços mais de cada arquivos no diretório atual e todas as subpastas .. para verificar o status globstar em sua sessão atual:shopt -p globstar
. Para globstar ativar:shopt -s globstar
.• utlity "file" :
if [[ $(file "$f") =~ pdf ]]; then ...
para verificar o formato real do arquivo em pdf - mais robusto do que testar apenas a extensão do arquivo• basename, dirname : para comparar o nome do arquivo com o nome do diretório imediatamente acima dele.
basename
retorna o nome do arquivo -dirname
retorna o caminho completo do diretório - combine as duas funções para retornar apenas o diretório que contém o arquivo correspondente. Coloquei cada um em uma variável ( _mydir e _myf ) para fazer um teste simples usando = ~ para correspondência de string.Uma subtilidade: remova qualquer "ponto" no nome do arquivo para evitar que ele corresponda ao diretório atual, cujo atalho também é "." - Usei a substituição direta de strings na variável _myf :
${_myf//./}
- não é muito elegante, mas funciona. Partidas positivas irá retornar o caminho de cada arquivo - juntamente com o caminho completo da pasta atual precedendo a saída com:$(pwd)/
.Código
fonte