Estou tentando remover a extensão de nome de arquivo de uma lista de arquivos que gerei com o seguinte script bash:
#!/bin/bash file_list=$(find . -type f) #assuming that the files are stored in the same directory trimmed_file_list=$(printf "%s\n" "${file_list[@]%.*}") printf "%s\n" "${trimmed_file_list[@]}"
Esta expansão remove a extensão da última entrada na lista, mas não nenhuma das anteriores.
Por exemplo, quero a seguinte lista:
file1.pdf file2.pdf file3.png
Tornar-se
file1 file2 file3
Mas em vez disso, recebo:
file1.pdf file2.pdf file3
Eu prefiro não fazer isso em um loop, gostaria de usar a expansão de parâmetro. Quero evitar o corte porque sempre quero remover a última extensão do arquivo.
Há um bom número de tópicos sobre expansão de parâmetros e parece que o bash pode estar engasgando com find
” s uso de novas linhas … Não tenho certeza. Se outro dos tópicos pré-existentes explica esse problema, não entendo totalmente o que está acontecendo.
Tópicos que parecem relacionado, mas não parece resolver meu problema:
- Como posso remover a extensão de um nome de arquivo em um script de shell?
- Expansão do parâmetro Shell em matrizes
- Eliminando o nome do arquivo extensões com find -exec
Comentários
- Seu título menciona matrizes, mas não há nenhuma matriz em seu código.
- @Kusalananda Obrigado! Eu ‘ comecei a perceber isso desde que perguntei. Ainda aprendendo 🙂
- @Kusalananda I ‘ Fui em frente e modifiquei a pergunta para corresponder melhor ao problema. Isso deve evitar que pesquisas erradas no Google atinjam a página. Obrigado pela informação!
Resposta
Você poderia fazer tudo em um comando.
find /path/to -type f -execdir bash -c "printf "%s\n" "${@%.*}"" bash {} +
Comentários
- Obrigado! Na verdade, preciso criar algumas cópias da matriz, uma para um menu que tem o nome do arquivo modificado e outra que manterá o valor do índice original para que eu possa chamar o arquivo do menu. É realmente incrível o quanto o bash pode fazer! A capacidade de incorporar tudo em um comando ainda me surpreende! : D
Resposta
Acredito que você gostaria de fazer uma matriz em vez de uma string:
IFS=$"\n" # split on newline only set -o noglob # disable the glob part file_list=($(find . -name "*.*" -type f))
Ou com bash 4.4+, não interrompendo caminhos de arquivo com caracteres de nova linha:
readarray -td "" file_list < <(find . -name "*.*" -type f -print0)
Então sua expansão de parâmetro deve funcionar, embora aqui faça mais sentido usar uma variável de matriz novamente:
trimmed_file_list=("${file_list[@]%.*}")
Em seu exemplo de código, você está criando uma string em seguida, pedindo a expansão do parâmetro para remover tudo após o caractere de ponto final na string completa.
Comentários
- Obrigado! Vou testá-lo assim que chegar à minha mesa pela manhã.
- Isso pressupõe que nenhum nome de arquivo nesse diretório contenha espaços em branco ou caracteres globbing.
- @Wildcard, deve ser endereçado pela última edição.
- @Wildcard Obrigado pelo ponteiro! Eu ‘ estou gerando os arquivos que são colocados neste diretório programaticamente para que não ‘ seja um problema.
Resposta
Seu código não inclui nenhum array. Além disso, ele coloca uma lista de nomes de arquivos em uma string, $file_list
. O conteúdo da string terminará com file3.png
e sua substituição de parâmetro remove .png
da string, deixando você com uma única string de nomes de arquivos onde o último nome de arquivo não tem um sufixo de nome de arquivo.
Colocar vários objetos separados (nomes de caminhos) em uma única string desqualifica automaticamente o script de funcionar corretamente para arquivos cujos nomes contêm espaços (ou qualquer delimitador que a string usa). Usar uma matriz não ajudaria, pois você ainda dividiria a saída de find
em espaços em branco.
Para cortar a extensão de todos os nomes de arquivo de arquivos regulares dentro ou abaixo do diretório atual:
find . -type f -name "*.*" -exec sh -c " for pathname do printf "Would move %s to %s...\n" "$pathname" "${pathname%.*}" # mv -i "$pathname" "${pathname%.*}" done" sh {} +
Procura por arquivos regulares cujos nomes contenham pelo menos um ponto. Os nomes de caminho desses arquivos são alimentados em lotes em um pequeno script de shell que executa um loop sobre eles. O script de shell renomeia os arquivos removendo o último ponto do nome do arquivo e tudo o que vem depois. O comando mv
real é comentado por questões de segurança.
O comando find
atua como um gerador de nomes de caminho para o shell script interno, e temos a garantia de processar corretamente os nomes de caminho contendo espaços, novas linhas e tabulações. Não há necessidade de armazenar a saída dos comandos em variáveis.
Se você tiver uma matriz de nomes de caminho, possivelmente criada usando
shopt -s globstar nullglob file_list=( **/*.* ) # get pathnames of files with dots in their names
Então você seria capaz de produzir os nomes de caminho sem sufixos com
printf "%s\n" "${file_list[@]%.*}"
Se isso ajudaria você, eu não sei. Se você quiser usar os nomes de caminho sem sufixos para algo , então, usar a saída do comando printf
acima seria a coisa errada a fazer (você voltaria a não manipular nomes de caminhos estranhos novamente). e como você exclui os sufixos de nome de arquivo depende do que você gostaria de fazer com o resultado.
Relacionado:
Comentários
- Obrigado! Seu domínio do bash é muito evidente! Eu ‘ ainda estou lutando contra a superfície … Obrigado por dedicar seu tempo para ajudar 🙂