Como obter a parte do nome do arquivo de um caminho de uma variável do shell

0

Uma variável do shell contém um caminho. Como se obtém a parte do nome do arquivo?

No bash (1), experimentei e descobri que posso fazer isso com ."${i/*\///}" , em que i é o nome da variável de ambiente. Esse método não é apenas feio, mas também errôneo no caso em que o caminho não contém nenhum caractere / .

Vou demonstrar um caso prático em que tal função é necessária. Digamos que queremos criar um link simbólico para todos os arquivos PDF em um diretório de origem para o diretório atual.

$ for i in /source/path/*.pdf; do\
  ln -s "$i" ."${i/*\///}"; \
  done
    
por Peer Gynt 24.09.2018 / 04:58

2 respostas

4

${i##*/}

Isso funciona em shells Posix, incluindo bash , dash , ksh , zsh , etc. Do padrão Parte de Expansão do Parâmetro POSIX do Posix Shell & Especificação de utilitários:

${parameter##[word]}
Remove Largest Prefix Pattern. The word shall be expanded to produce a pattern. The parameter expansion shall then result in parameter, with the largest portion of the prefix matched by the pattern deleted.

Como alternativa, e tradicionalmente, o comando basename foi usado para essa finalidade. Cuidado: O desempenho pode se tornar um problema significativo porque basename é implementado como um comando externo (por exemplo, /usr/bin/basename ). Como você está executando isso dentro de um loop, você chamará um comando externo para cada arquivo. Em uma lista de 1000 arquivos, isso pode ser a diferença entre 0,05 segundos (expansão de parâmetro) e 2,0 segundos (comando basename ). Mas para uma lista de 10.000 arquivos, pode ser a diferença entre 0,5 segundos (expansão) versus 20 segundos ( basename ). A diferença no desempenho torna-se mais extrema à medida que o número de arquivos aumenta.

Para facilitar a leitura e melhorar o desempenho, você pode implementar sua própria função basename , por exemplo:

mybasename() { echo "${1##*/}"; }

(A seleção de um nome melhor para a função e / ou a implementação da interface de linha de comando basename completa é deixada como um exercício para o leitor.)

    
por 24.09.2018 / 05:07
0

Você pode colocar o caminho em uma variável e usar sua contagem de comprimento para obter apenas a subseqüência desejada do nome do caminho completo, assim:

$ pth="/source/path/";
$ for i in $path*.pdf; do \
  ln -s "$i" ./"${i:${#pth}}"; \
  done
    
por 24.09.2018 / 09:14