Como remover extensão de nome de arquivo de uma lista de nomes de arquivos no bash

0

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:

por Shrout1 13.08.2018 / 22:49

3 respostas

3

Você pode fazer tudo em um único comando.

find /path/to -type f -execdir bash -c 'printf "%s\n" "${@%.*}"' bash {} +
    
por 14.08.2018 / 04:50
1

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:

por 14.08.2018 / 10:13
1

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.

    
por 14.08.2018 / 00:09