Substituir pontos no nome do arquivo por sublinhados, exceto a extensão

9

Alguém pode sugerir como renomear o nome do arquivo:

head.body.date.txt

Para:

head_body_date.txt

Existe uma instrução de linha única para fazer a renomeação em Unix ?

    
por S G 11.10.2016 / 05:46

6 respostas

8

Itere sobre os nomes dos arquivos e use a expansão Parâmetro para conversão:

for f in *.*.*.txt; do i="${f%.txt}"; echo mv -i -- "$f" "${i//./_}.txt"; done

O padrão de expansão de parâmetro, ${f//./_} , substitui todos os . s por _ s no nome do arquivo ( $f ).

O texto acima será executado em seco, para permitir a renomeação real, remover echo :

for f in *.*.*.txt; do i="${f%.txt}"; mv -i -- "$f" "${i//./_}.txt"; done

Se você quiser lidar com qualquer extensão, não apenas .txt :

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     echo mv -i -- "$f" "${pre//./_}.${suf}"; done

Após a verificação, remova echo da ação real:

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     mv -i -- "$f" "${pre//./_}.${suf}"; done

Genérico, para um número arbitrário de pontos, pelo menos um:

for f in *.*; do pre="${f%.*}"; suf="${f##*.}"; \
                 mv -i -- "$f" "${pre//./_}.${suf}"; done
    
por 11.10.2016 / 05:51
4

com perl com base em rename

$ rename -n 's/\.[^.]+$(*SKIP)(*F)|\./_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)
  • \.[^.]+$(*SKIP)(*F) pula esse padrão e procura por correspondências alternativas
  • |\./_/g substitui todo . por _

Ou, usando lookahead negativo

$ rename -n 's/\.(?![^.]+$)/_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)

Quando isso estiver correto, remova a opção -n

    
por 11.10.2016 / 05:57
3
rename 's/\.(?=[^.]*\.)/_/g' *.txt

Usa a substituição do regex para localizar todas as instâncias, exceto a última, de . no nome do arquivo (nona capture lookahead) e substituí-las por _ . Generalises para *.* se você quiser.

(esta versão específica de rename parece estar instalada via util-linux ). Estou usando Ubuntu 12.04 (sim, máquina gravemente desatualizada).

    
por 11.10.2016 / 06:59
2

bash :

old=head.body.date.txt oldb=${old%.*} olde=${old##*.} ; \
mv -- "$old" "${oldb//./_}.${olde}"
    
por 11.10.2016 / 06:34
1

Usando mv , sed e rev em uma linha:

mv "head.body.date.txt" "$(echo head.body.date.txt | rev | sed 's/\./_/2g' | rev)"

Se você quiser aplicá-lo em todos os arquivos txt no representante atual, usar globs parece complicado devido a como mv funciona, mas você pode fazer um loop for em uma linha:

for file in *.txt; do mv "$file" "$(echo $file | rev | sed 's/\./_/2g' | rev)"; done

Um pouco mais longo, mas você pode combinar vários padrões no seu loop!

    
por 11.10.2016 / 11:36
-1
 mv head.body.date.txt head_body_date.txt

É tão simples quanto isso para um único arquivo por vez. Você não especifica se deseja que isso seja feito recursivamente dentro de um diretório ou para todo o diretório, de modo que seria sua solução mais conveniente e rápida.

    
por 11.10.2016 / 16:47