Você pode fazer tudo em um único comando.
find /path/to -type f -execdir bash -c 'printf "%s\n" "${@%.*}"' bash {} +
Estou tentando remover a extensão de nome de arquivo de uma lista de arquivos que geramos com o seguinte script:
#!/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 apara a extensão da entrada última da lista, mas não de nenhuma das anteriores.
Por exemplo, eu quero a seguinte lista:
file1.pdf
file2.pdf
file3.png
Para se tornar
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. Eu quero evitar o corte porque eu só quero remover a última extensão no arquivo.
Há um número razoável de tópicos sobre expansão de parâmetros e parece que o bash pode estar sufocando com o uso de novas linhas de find
... Eu realmente não tenho certeza. Se outro dos tópicos preexistentes explicar essa questão, não entendo completamente o que está acontecendo.
Tópicos que parecem relacionados, mas não parecem resolver meu problema:
Você pode fazer tudo em um único comando.
find /path/to -type f -execdir bash -c 'printf "%s\n" "${@%.*}"' bash {} +
Seu código não inclui matrizes. 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 removerá .png
da string, deixando você com uma única string de nomes de arquivos em que o último nome de arquivo não possui um sufixo de nome de arquivo.
Colocar vários objetos separados (nomes de caminho) em uma única cadeia de caracteres desqualifica automaticamente o script de trabalhar adequadamente para arquivos cujos nomes contenham espaços (ou qualquer outro delimitador que a cadeia 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 arquivos comuns no diretório atual ou abaixo dele:
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 {} +
Isso 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 faz um loop sobre eles. O script de shell renomeia os arquivos removendo o último ponto no nome do arquivo e tudo o que vem depois. O comando mv
real é comentado por segurança.
O comando find
atua como um gerador de nomes de caminhos para o script de shell interno, e temos a garantia de processar corretamente nomes de caminho contendo espaços, novas linhas e tabulações. Não há necessidade de armazenar a saída de comandos em variáveis.
Se você tiver uma matriz de nomes de caminhos, possivelmente criados 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 ser feita (você estaria de volta por não lidar com o caminho estranho novamente). Então, quando e como você excluir os sufixos do nome do arquivo depende do que você gostaria de fazer com o resultado.
Relacionados:
Eu acredito que você gostaria de criar 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 o bash 4.4+, sem quebrar caminhos de arquivo com caracteres de nova linha:
readarray -td '' file_list < <(find . -name '*.*' -type f -print0)
Em seguida, a expansão dos seus parâmetros deve funcionar, mas aqui faria mais sentido usar uma variável array novamente:
trimmed_file_list=("${file_list[@]%.*}")
No seu exemplo de código, você está fazendo uma string, em seguida, pedindo expansão de parâmetro para remover tudo após o caractere de ponto final na cadeia completa.