O GNU find
tem um predicado -iwholename
que resolve meu problema:
find . -iwholename ./impl/src/main/java/org/jboss/weld/util/collections/multimaps.java
Para obtê-lo em uma variável:
cased='find . -iwholename "$filepath"'
Eu tenho uma lista de caminhos de arquivos armazenados, por exemplo ( impl/src/main/java/org/jboss/weld/util/collections/multimaps.java
). Os caminhos foram convertidos para minúsculas antes de serem armazenados.
Agora, preciso acessar o arquivo em um script bash. Existe um comando simples para "consertar" o case e encontrar o arquivo? Para simplificar, suponha que não haja várias versões do arquivo com casos diferentes. Note também que os diretórios no caminho podem precisar ter seu gabinete fixo.
Pensei em usar o find, mas você não pode ter um caminho completo, portanto, a partir da raiz find . -iname multimaps.java
pode retornar vários arquivos, apenas um deles está na estrutura de diretórios correta.
Eu preciso do caminho correto para terminar em uma variável em um script bash.
com zsh
:
setopt extendedglob
files=((#i)${(f)^"$(<file.list)"}(N))
printf '%s\n' $files
(onde file.list
é o arquivo que contém essa lista de caminhos em minúsculas, um por linha).
(#i)
: glob insensitivo a maiúsculas e minúsculas (precisa de extendedglob
) ${(f)"$expansion"}
: dividir a expansão nos feeds de linha (nova linha) ${^array}
: do tipo de expansão de contraventamento para a matriz. (N)
: qualificador de globglob null (remove globs que não correspondem). Para um único arquivo, é apenas:
setopt extendedglob
file=impl/src/main/java/org/jboss/weld/util/collections/multimaps.java
matches=((#i)$file)
(aqui omitindo o (N)
, então você recebe um erro se não houver correspondência)
O ksh93
equivalente seria:
matches=(~(iN)"$file") # N for nullglob, otherwise the glob expands to itself
# instead of giving an error when it doesn't match.
bash
tem uma opção nocaseglob
para corresponder insensivelmente a maiúsculas e minúsculas. No entanto
matches=($file)
não funciona. Você precisaria ativar globbing (usando qualquer um dos operadores glob) para cada componente de caminho como em
shopt -s nocaseglob nullglob
matches=([i]mpl/[s]rc/[m]ain/[j]ava/[o]rg/[j]boss/[w]eld/[u]til/[c]ollections/[m]ultimaps.java)
Com qualquer shell com suporte para um operador [...]
glob (portanto, em essência, todos menos fish
), você também pode reescrever o glob como [iI][mM][pP][lL]/[sS][rR]...
e assim por diante.
Observe que é diferente de um find . -ipath "./$file"
em que o shell não precisa rastrear toda a árvore de diretórios. Primeiro lê o diretório atual para encontrar diretórios (ou links simbólicos para diretórios! Outra diferença de find
) chamada impl
ou Impl
ou ImPl
, etc., então, lê apenas o conteúdo desses diretórios para encontrar alguns src
/ SRC
/ srC
etc. e assim por diante.
Outra diferença é que ele ainda funciona corretamente se os componentes de caminho contiverem operadores glob (como impl/***src***/whatever
).
No bash:
shopt -s nocasematch globstar
for f in **; do for search in "${files[*]}"; do [[ $f == $search ]] && echo Found "$search" at: "$f"; done; done
A opção shell do nocasematch diz ao comando [[ ... == ... ]]
para ignorar maiúsculas e minúsculas ao comparar strings. O shell globstar ativa a emulação bash de força bruta **
de find
; ele difere de find
em que ele irá ignorar os arquivos de pontos (a menos que shopt -s dotglob
esteja definido) e siga os links simbólicos.
Uma abordagem para evitar a varredura da árvore repetidamente para cada arquivo seria listar a árvore de diretórios uma vez e, em seguida, procurar a conversão em letras minúsculas do caminho em uma tabela de hash. Por exemplo com:
NL='
'
find . -name "*$NL*" -prune -o -print | awk '
!list_processed {paths["./" $0]; next}
tolower($0) in paths' file.list list_processed=1 -
(onde file.list
contém a lista de arquivos em minúsculas, um por linha).
Estamos pulando os arquivos (e não entrando em diretórios) com novas linhas em seus nomes, já que eles não podem ser armazenados na file.list
se essa lista for delimitada por nova linha (e isso quebraria o pós-processamento).
Observe, entretanto, que o salto não funcionará se os nomes dos arquivos também contiverem caracteres inválidos. Veja a seção byte vs character em Por que o looping está causando má prática de saída? para mais detalhes.
Tags find ubuntu shell-script