Linux: renomeia o arquivo, mas mantém a extensão?

9

No Windows / DOS, posso dizer rename myfile.* yourfile.* para alterar o nome, mas manter a extensão. Como isso é feito no Linux?

A página man apenas sugere como alterar a extensão, mas isso é o oposto do que eu quero.

Bônus:
Eu realmente quero colocar a data de criação de uma foto em seu nome de arquivo, para obter algo como 20091231 2359 New Year.jpg . Eu tenho medo de precisar de alguma combinação não trivial de comandos para conseguir isso?

    
por Torben Gundtofte-Bruun 01.01.2010 / 11:08

8 respostas

13

Aqui está uma resposta para a questão bônus.

I actually want to put a photo's creation date into its filename, to get something like 20091231 2359 New Year.jpg. I'm afraid that I need some non-trivial combination of commands to achieve that?

Supondo que você queira tirar a data de criação da foto dos dados EXIF, você precisará de uma ferramenta separada para isso. Felizmente, verifica-se que o jhead oferece uma maneira trivial de fazer exatamente o que você quer, com seu -n opção.

$ jhead -h
 [...]

 -n[format-string]

             Rename files according to date.  Uses exif date if present, file
             date otherwise.  If the optional format-string is not supplied,
             the format is mmdd-hhmmss.  If a format-string is given, it is
             is passed to the 'strftime' function for formatting
             In addition to strftime format codes:
             '%f' as part of the string will include the original file name
             [...]

Veja um exemplo:

$ jhead -n%Y-%m-%d-%f New_year.jpg   
New_year.jpg --> 2009-12-31-New_year.jpg

Editar : claro, para fazer isso para um monte de fotos, seria algo como:

$ for i in *jpg; do jhead -n%Y-%m-%d-%f $i; done

Para ajustar a formatação da data ao seu gosto, observe a saída de date --help , por exemplo; listará os códigos de formato disponíveis.

(o jhead é amplamente disponível para sistemas diferentes. Se você está, por exemplo, no Ubuntu ou Debian, simplesmente digite sudo apt-get install jhead para instalá-lo.)

    
por 01.01.2010 / 11:37
10

Para apenas a parte de renomeação, o programa 'renomear' funcionará. É o mesmo que o exemplo que você viu na página de manual, apenas mudou de lugar.

justin@eee:/tmp/q$ touch myfile.{a,b,c,d}
justin@eee:/tmp/q$ ls
myfile.a  myfile.b  myfile.c  myfile.d
justin@eee:/tmp/q$ rename -v s/myfile/yourfile/ myfile.*
myfile.a renamed as yourfile.a
myfile.b renamed as yourfile.b
myfile.c renamed as yourfile.c
myfile.d renamed as yourfile.d
justin@eee:/tmp/q$ ls
yourfile.a  yourfile.b  yourfile.c  yourfile.d
justin@eee:/tmp/q$ 
    
por 01.01.2010 / 16:16
7
betelgeuse:tmp james$ ls myfile.* yourfile.*
ls: yourfile.*: No such file or directory   
myfile.a    myfile.b
betelgeuse:tmp james$ for file
> in myfile.*
> do
> mv "${file}" "'echo $file | sed 's/myfile\./yourfile./''"
> done
betelgeuse:tmp james$ ls myfile.* yourfile.*
ls: myfile.*: No such file or directory
yourfile.a  yourfile.b

A chave é que, se você tiver visto um exemplo que mostre como inserir uma parte do nome do arquivo com um regex, esse é o único exemplo que você precisa. As extensões não têm status especial nos sistemas de arquivos unix - elas são apenas uma parte do nome do arquivo que acontece depois de um caractere . .

    
por 01.01.2010 / 12:18
4

Aqui estão algumas maneiras diferentes de manipular nomes de arquivos

for f in *.jpg
do
    mv "$f" "before_part${f%.*}after_part.${f##*.}"
    # OR mv "$f" "before_part$(basename "$f" ".jpg")after_part.jpg"
done

As expansões de parâmetros no comando mv funcionam como segue:

${f%.*} - Exclua o padrão de correspondência mais curto do final da string contida em $f , nesse caso, exclua tudo após e incluindo o último ponto. O único % significa "o menor do final".

${f##*.} - Exclua o padrão de correspondência mais longo do início da string contida em $f , nesse caso, tudo antes e incluindo o último ponto (isso inclui também outros pontos). O duplo # ( ## ) significa "mais longo desde o início".

Então, por exemplo, se $f contiver "Foo.bar.baZ.jpg":

echo "${f%.*}"

Foo.bar.baZ

e

echo "${f##*.}"

jpg

Assim, o comando mv , uma vez expandido, seria semelhante:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"
    
por 01.01.2010 / 15:03
3

Não há extensões de nome de arquivo no Linux.

Use expressões regulares para cortar subseqüências particulares do nome do arquivo e acessá-las.

Exemplo:

Cenário da vida real: você está extraindo html de um arquivo chm. Os nomes de arquivos no Windows não diferenciam maiúsculas de minúsculas, portanto, no Linux, você obterá links quebrados. Você tem um arquivo chamado index.HTML , mas href="index.html" em URLs. Portanto, seu objetivo é adaptar nomes de arquivos para corresponder a links para eles.

Suponha que você tenha o nome do arquivo em uma variável:

FILENAME='index.HTML'

A partir da versão 3.0, o bash suporta expressões regulares, assim você não precisa de nenhuma ferramenta adicional como o grep / sed / perl etc para executar manipulação de strings. O exemplo a seguir ilustra a substituição de uma correspondência de backend em uma string:

echo ${FILENAME/%\.HTML/.html}

As sequências de correspondência e substituição podem ser parametrizadas, se você desejar, isso fornece flexibilidade adicional ao escrever scripts. O snippet de código a seguir atinge o mesmo objetivo:

match='\.HTML'
replacement='.html'
echo ${FILENAME/%$match/$replacement}

Consulte os documentos bash para informações adicionais.

    
por 01.01.2010 / 11:16
0

Aqui está outro:

find -name "*.jpg" -printf '"%p" "%h/%TY%Tm%Td %TH%TM %f"\n' | while read -r f
do
    eval "mv ${f}"
done
    
por 01.01.2010 / 15:37
0

Sempre há mais de uma maneira de fazer isso. Eu coloquei o seguinte script como / usr / local / bin / mrename.

Em seguida, no script que contém os arquivos de foto, basta digitar: mrename

Há também um recurso opcional com comentário no script para escalar as fotos (usando o ImageMagick).

Espero que isso seja útil para algumas pessoas.

#!/usr/bin/perl
#
# mrename files
#
#
use strict;

# if no 2 args, use defaults
my $dir = ".";

# read in path from command line
$dir = $ARGV[0] if ( defined( $ARGV[0] ) && $ARGV[0] ne "" );

# read in directory contents
opendir( DIR, $dir );
my @files = readdir( DIR );
closedir( DIR );

# rename and/or scale each file in directory
my $number_of_files = scalar( @files );
my $curfile = 0;

foreach my $file( @files ) {
    # only rename and scale jpg/gif files
    if ( $file =~ /\w+\.(jpg)$/ ) {
        my $extension = $1;
        $extension =~ tr/A-Z/a-z/;
        my $full_filename = "$dir/$file";

        # get stats on file- specifically the last modified time
        (my $dev,my $ino,my $mode,my $nlink,my $uid,my $gid,my $rdev,my $size,
        my $atime,my $mtime,my $ctime,my $blksize,my $blocks) = stat($full_filename);

        # convert last-modified time from seconds to practical datetime terms
        (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,
        my $isdst) = localtime($mtime);

        ++$mon;
        $year += 1900;

        my $filecdate = sprintf( "m%04i%02i%02i_%02i%02i%02i.$extension", $year, $mon, $mday, $hour, $min, $sec );
        my $full_newfilename = "$dir/$filecdate";

        # to scale files, use imagemagick by using the command below instead of mv 
        #my $cmd = "convert $full_filename -resize $scale% $full_newfilename";
        my $cmd = "mv $full_filename $full_newfilename";
        system( $cmd );

        # update percentage done
        my $percent_done = sprintf( "%5.2lf", 100* (++$curfile) / $number_of_files );
        print "\r$percent_done%";
    }
}
print "\n";
    
por 01.01.2010 / 17:48
0

Você pode usar a opção -X/--keep-extension com rename (versão 1.600):

-X, --keep-extension Save and remove the last extension from a filename, if there is any. The saved extension will be appended back to the filename at the end of the rest of the operations.

rename está disponível para Mac do Homebrew e para Linux do Linuxbrew (entre outras opções de instalação, é claro).

    
por 10.11.2017 / 13:52