Como renomear com prefixo / sufixo?

95

Como faço mv original.filename new.original.filenamesem redigitar o nome do arquivo original?

Eu imaginaria ser capaz de fazer algo parecido mv -p=new. original.filenameou talvez mv original.filename new.~ou o que seja - mas não consigo ver nada assim depois de olhar para man mv/ info mvpages.

Claro, eu poderia escrever um script de shell para fazer isso, mas não existe um comando / sinalizador existente para ele?

Peter Boughton
fonte

Respostas:

122

Em Bash e zsh você pode fazer isso com Brace Expansão . Isso simplesmente expande uma lista de itens entre colchetes. Por exemplo:

# echo {vanilla,chocolate,strawberry}-ice-cream
vanilla-ice-cream chocolate-ice-cream strawberry-ice-cream

Portanto, você pode renomear da seguinte maneira:

mv {,new.}original.filename

conforme isso se expande para:

mv original.filename new.original.filename
Dave Webb
fonte
Obrigado, esta parece ser a melhor solução - também funciona com ksh.
Peter Boughton,
29
O que isso não funciona é com curingas. Ou seja, em um diretório contendo nomes de arquivo a, b, c, usando "echo {, novo.} *" Produz a lista "abc novo. *" (Porque a geração de nome de arquivo via expansão de chave ocorre antes de expandir caracteres curinga - pelo menos por inferência).
Jonathan Leffler
Há meses estou procurando por uma solução desse tipo usando apenas a funcionalidade básica do shell ... Eu nunca teria criado algo tão simples, muito obrigado!
flonk em
Obrigado pela referência à Expansão do Brace :-) exatamente o que eu estava procurando!
Pim Hazebroek
1
Eu amo o exemplo Estou com vontade de ir para Baskin Robbins durante a hora do almoço agora.
Sridhar Sarnobat
156

Você pode usar o rename(1)comando:

rename 's/(.*)$/new.$1/' original.filename

Editar: Se renamenão estiver disponível e você precisar renomear mais de um arquivo, o script de shell pode ser realmente curto e simples para isso. Por exemplo, para renomear todos*.jpg para prefix_*.jpgno diretório atual:

for filename in *.jpg; do mv "$filename" "prefix_$filename"; done;
Simon Lehmann
fonte
O grafite foi instalado neste fim de semana, e eles têm uma etapa que é essencialmente ("copiar todos os arquivos * .example para a pasta conf, removendo o sufixo example"). Realmente preguiçoso da parte deles, mas rename 's/(.*).example/$1/' *.exampleme salvou do tédio.
Conrad.Dean
2
Esta é a melhor resposta até agora.
lifeisfoo
Não acho que você precise do primeiro $neste cenário. Então's/(.*)/new.$1/'
wisbucky,
1
renamecomando não funciona em minha máquina RHEL 6. Existem versões diferentes deste comando? O for ... donefuncionou para mim.
roubo de
25

Você pode obter uma renomeação de vários arquivos compatível com Unix (usando curingas) criando um loop for:

for file in *; do
  mv $file new.${file%%}
done
Um Muguro
fonte
7
Qual é a diferença entre isso e o que Simon Lehmann já respondeu ?
Peter Boughton
4
Isso funciona muito bem. O que ${file%%}fazer? Parece semelhante a simplesmente $ {file}
Sidmitra
Também estou curioso sobre $ {file %%}
Lucas Bustamante
10

Já vi pessoas mencionarem um renamecomando, mas ele não está rotineiramente disponível em sistemas Unix (ao contrário de sistemas Linux, digamos, ou Cygwin - em ambos, renomear é um executável em vez de um script). Essa versão do renametem uma funcionalidade bastante limitada:

rename from to file ...

Ele substitui o de parte dos nomes de arquivos com o que , e o exemplo dado na página do manual é:

rename foo foo0 foo? foo??

Isso renomeia foo1 para foo01 e foo10 para foo010, etc.

Eu uso um script Perl chamado rename, que originalmente tirei da primeira edição do livro Camel, por volta de 1992, e depois estendi, para renomear arquivos.

#!/bin/perl -w
#
# @(#)$Id: rename.pl,v 1.7 2008/02/16 07:53:08 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command

use strict;
use Getopt::Std;

my(%opts);
my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;

die $usage unless getopts('fnxV', \%opts);

if ($opts{V})
{
    printf "%s\n", q'RENAME Version $Revision: 1.7 $ ($Date: 2008/02/16 07:53:08 $)';
    exit 0;
}
$force = 1 if ($opts{f});
$noexc = 1 if ($opts{n});
$trace = 1 if ($opts{x});

my($op) = shift;
die $usage unless defined $op;

if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}

for (@ARGV)
{
    if (-e $_ || -l $_)
    {
        my($was) = $_;
        eval $op;
        die $@ if $@;
        next if ($was eq $_);
        if ($force == 0 && -f $_)
        {
            print STDERR "rename failed: $was - $_ exists\n";
        }
        else
        {
            print "+ $was --> $_\n" if $trace;
            print STDERR "rename failed: $was - $!\n"
                unless ($noexc || rename($was, $_));
        }
    }
    else
    {
        print STDERR "$_ - $!\n";
    }
}

Isso permite que você escreva qualquer substituto Perl ou comando de transliteração para mapear nomes de arquivo. No exemplo específico solicitado, você usaria:

rename 's/^/new./' original.filename
Jonathan Leffler
fonte
Obrigado, se eu pudesse aceitar uma segunda resposta, seria esta. Eu queria um comando padrão como algo que funcionasse em qualquer coisa que eu pudesse usar, mas posso colocar esse script nas máquinas que uso com frequência e ainda será útil.
Peter Boughton,
James Wong observa que, para Arch Linux, você poderia simplesmente baixar e instalar este script via pacmanusando: pacman -Sy perl-rename. Em seguida, adicione um alias a ele em seu bashrc:alias rename='perl-rename'
Jonathan Leffler
e se "de" ou "para" forem strings vazias, ou seja, você deseja acrescentar algo a cada nome de arquivo ou remover algo completamente
Troyseph
1
@Troyseph - para anexar '.htmlaos nomes dos arquivos, use 's/$/.html/'- para remover tmpde qualquer lugar nos nomes dos arquivos, use 's/tmp//g'(localizar tmpe substituir por nada em todos os lugares).
Jonathan Leffler
4

A maneira mais fácil de renomear arquivos em massa no diretório é:

ls | xargs -I fileName mv fileName fileName.suffix
Brajan Elektro
fonte
2

Se estiver aberto a uma modificação, você pode usar um sufixo em vez de um prefixo. Depois, você pode usar o preenchimento com tabulação para obter o nome do arquivo original e adicionar o sufixo.

Caso contrário, não, isso não é algo compatível com o comando mv. Um script de shell simples pode lidar, no entanto.

workmad3
fonte
Freqüentemente, desejo os dois, mas principalmente o prefixo - como você disse, o preenchimento com tabulação pode lidar com sufixos.
Peter Boughton,
1

No meu caso, tenho um grupo de arquivos que precisa ser renomeado antes de poder trabalhar com eles. Cada arquivo tem sua própria função no grupo e seu próprio padrão.

Como resultado, tenho uma lista de comandos de renomeação como esta:

f=`ls *canctn[0-9]*`   ;  mv $f  CNLC.$f
f=`ls *acustb[0-9]*`   ;  mv $f  CATB.$f
f=`ls *accusgtb[0-9]*` ;  mv $f  CATB.$f
f=`ls *acus[0-9]*`     ;  mv $f  CAUS.$f

Experimente também:

f=MyFileName; mv $f {pref1,pref2}$f{suf1,suf2}

Isso produzirá todas as combinações com prefixos e sufixos:

pref1.MyFileName.suf1
...
pref2.MyFileName.suf2

Outra maneira de resolver o mesmo problema é criar uma matriz de mapeamento e adicionar o prefixo corpondent para cada tipo de arquivo, conforme mostrado abaixo:

#!/bin/bash
unset masks
typeset -A masks
masks[ip[0-9]]=ip
masks[iaf_usg[0-9]]=ip_usg
masks[ipusg[0-9]]=ip_usg
...
for fileMask in ${!masks[*]}; 
do  
registryEntry="${masks[$fileMask]}";
fileName=*${fileMask}*
[ -e ${fileName} ] &&  mv ${fileName} ${registryEntry}.${fileName}  
done
Aprodan
fonte
1

Renomear arquivos em massa script bash

#!/bin/bash
# USAGE: cd FILESDIRECTORY; RENAMERFILEPATH/MultipleFileRenamer.sh FILENAMEPREFIX INITNUMBER
# USAGE EXAMPLE: cd PHOTOS; /home/Desktop/MultipleFileRenamer.sh 2016_
# VERSION: 2016.03.05.
# COPYRIGHT: Harkály Gergő | mangoRDI (https://wwww.mangordi.com/) 

# check isset INITNUMBER argument, if not, set 1 | INITNUMBER is the first number after renaming
if [ -z "$2" ]
    then i=1;
else
    i=$2;
fi

# counts the files to set leading zeros before number | max 1000 files
count=$(ls -l * | wc -l)
if [ $count -lt 10 ]
    then zeros=1;
else
    if [ $count -lt 100 ]
        then zeros=2;
    else
        zeros=3
    fi
fi

# rename script
for file in *
do
    mv $file $1_$(printf %0"$zeros"d.%s ${i%.*} ${file##*.})
    let i="$i+1"
done
Harkály Gergő
fonte
0

Eu sei que há ótimas respostas aqui, mas não encontrei nenhuma referência para lidar com extensões de nome de arquivo ao adicionar sufixo.

Eu precisava adicionar o sufixo '_en' a todos wav arquivos em uma pasta antes da extensão do arquivo.

A magia está aqui: %.*

for filename in *.wav; do mv $filename ${filename%.*}_en.wav; done;

Se você precisar lidar com diferentes extensões de arquivo, verifique esta resposta. Um pouco menos intuitivo.

yeya
fonte