Como renomear nomes de arquivos - substituindo sublinhados por espaços - em um script de linha de comando do shell

6

Estou tentando renomear todos os arquivos em uma pasta substituindo sublinhados por espaços.

i.e. this_is_a_test --> this is a test

mas de alguma forma estou bagunçando a citação

> for file in * ; do echo mv -v $file $(echo $file | sed 's/_/\ /g') ; done
mv -v this_is_a_test this\ is\ a\ test

parece OK, mas se eu remover o 'echo' mv reclama como se as barras invertidas tivessem sido removidas

> for file in * ; do mv -v $file $(echo $file | sed 's/_/\ /g') ; done
mv: target ‘test’ is not a directory

Alguém pode apontar o erro dos meus caminhos?

    
por ottotts 14.12.2013 / 10:02

5 respostas

3

Há um pequeno erro. Use "$newfile" em vez de apenas $newfile . Você precisa usar "

Aqui está o correto.

for file in * ; do mv -v "$file" "$(echo $file | sed 's/_/\ /g')" ; done

Se você tiver o nome de arquivo this_is_a_test , ele renomeará o arquivo para this\ is\ a\ test .

No caso, se você quiser renomear o arquivo para this is a test . Use o código abaixo,

for file in * ; do mv -v "$file" "$(echo $file | sed 's/_/ /g')" ; done

É uma boa prática usar variáveis dentro de "" enquanto você escreve um bom shell script.

    
por souravc 14.12.2013 / 10:29
6

Usando rename :

rename -n 's/_/ /g' *

Se tudo estiver correto, remova a opção -n :

rename 's/_/ /g' *
~/tmp$ tree
.
├── file
├── file_1
├── file_2
├── file_3
└── file_with_underscores

0 directories, 5 files
~/tmp$ rename 's/_/ /g' *
~/tmp$ tree
.
├── file
├── file 1
├── file 2
├── file 3
└── file with underscores

0 directories, 5 files
    
por kos 15.06.2015 / 18:17
3

Em vez de mv -v "$file" "$(echo $file | sed 's/_/\ /g')" , você pode usar um comando muito mais simples mv "$f" "${f//_/ }" .

Para adicioná-lo ao seu script:

for f in * ; do mv "$f" "${f//_/ }" ; done

E é isso.

    
por Maythux 15.06.2015 / 17:03
1

Use o comando find e rename :

find <your_start_folder> -type f -regex ".*_+.*" -exec rename 's/_/ /g' {}  \;

Este comando renomeia todos os arquivos com _ no nome do arquivo recursivamente.

Explicação

  • -regex ".*_+.*"

    Encontre todos os arquivos com pelo menos um _ no nome do arquivo

  • _

    Substitua todas as ocorrências de _

  • … com um caractere de espaço ( )

Exemplo

% ls -Rog
.:
total 4
drwxrwxr-x 2 4096 Jun 15 17:39 foo
-rw-rw-r-- 1    0 Jun 15 17:34 foo_bar

./foo:
total 0
-rw-rw-r-- 1 0 Jun 15 17:32 foo_bar

% find . -type f -regex ".*_+.*" -exec rename 's/_/ /g' {} \;

% ls -Rog                                                                 
.:
total 4
drwxrwxr-x 2 4096 Jun 15 17:40 foo
-rw-rw-r-- 1    0 Jun 15 17:34 foo bar

./foo:
total 0
-rw-rw-r-- 1 0 Jun 15 17:32 foo bar
    
por A.B. 15.06.2015 / 17:43
0

Aqui está uma versão do awk + for loop:

for filename in *; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done

E aqui está em ação

$ ls                                                                                                                                                  

$ echo "TEST" | tee {foo,bar}_{yolo,swag}_{whatever,else}.txt                                                                                         
TEST

$ ls
bar_swag_else.txt      bar_yolo_else.txt      foo_swag_else.txt      foo_yolo_else.txt
bar_swag_whatever.txt  bar_yolo_whatever.txt  foo_swag_whatever.txt  foo_yolo_whatever.txt

$ for filename in *; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done                                    

$ ls
bar swag else.txt      bar yolo else.txt      foo swag else.txt      foo yolo else.txt
bar swag whatever.txt  bar yolo whatever.txt  foo swag whatever.txt  foo yolo whatever.txt

Para considerar novas linhas e possíveis renomeamentos de diretórios, aqui está a típica construção de loop IFS + find + read + while. Após a sugestão, execute primeiro a versão com find . -type d -print0 , porque se você começar a renomear os arquivos primeiro, e um subdiretório contiver sublinhado, o nome do arquivo não será alterado. Resumidamente, cuide dos diretórios e subdiretórios primeiro, depois cuide dos arquivos

$ ls
file_bar_swag.txt  file_bar_yolo.txt  file_test_swag.txt  file_test_yolo.txt  foo_bar_swag.txt  foo_bar_yolo.txt  foo_test_swag.txt  foo_test_yolo.txt  tester_dir

$ ls tester_dir/                                                                                                                                                                                         
ber_sweg_elze.txt  ber_sweg_whut.txt  ber_yelo_elze.txt  ber_yelo_whut.txt  fee_sweg_elze.txt  fee_sweg_whut.txt  fee_yelo_elze.txt  fee_yelo_whut.txt

$  find . -type d -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done 
mv: ‘.’ and ‘./.’ are the same file

$ ls
file_bar_swag.txt  file_bar_yolo.txt  file_test_swag.txt  file_test_yolo.txt  foo_bar_swag.txt  foo_bar_yolo.txt  foo_test_swag.txt  foo_test_yolo.txt  tester dir

$  find . -type f -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done                                          
mv: ‘./.yolo’ and ‘./.yolo’ are the same file

$ ls
file bar swag.txt  file bar yolo.txt  file test swag.txt  file test yolo.txt  foo bar swag.txt  foo bar yolo.txt  foo test swag.txt  foo test yolo.txt  tester dir

Como você pode ver, há um pequeno problema - como o comando find também lista o diretório atual (simbolizado com um.), o comando criará um subproduto - um arquivo com um ponto à esquerda.

Adicionando ! -path . quando você lida com diretórios resolve o problema

$ find . ! -path .  -type d -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done                                

$ find .  -type f -print0 | while IFS="" read -r -d "" filename ; do NEWNAME=$(echo "$filename" | awk '{gsub("_"," "); print}'); mv "$filename" "$NEWNAME";done                                          

$ ls
file bar swag.txt  file bar yolo.txt  file baz swag.txt  file baz yolo.txt  foo bar swag.txt  foo bar yolo.txt  foo baz swag.txt  foo baz yolo.txt  tester dir

$ ls "tester dir"
file bar.txt  file baz.txt  foo bar.txt  foo baz.txt

$ ls -a
.  ..  file bar swag.txt  file bar yolo.txt  file baz swag.txt  file baz yolo.txt  foo bar swag.txt  foo bar yolo.txt  foo baz swag.txt  foo baz yolo.txt  tester dir
    
por Sergiy Kolodyazhnyy 15.06.2015 / 18:38