Corrigir Caminho do Caminho do Arquivo

3

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.

    
por Loren 08.05.2017 / 22:03

4 respostas

3

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"'
    
por 08.05.2017 / 22:05
3

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 ).

    
por 08.05.2017 / 22:12
1

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.

    
por 08.05.2017 / 22:56
1

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.

    
por 09.05.2017 / 08:39