Linux: переименовать файл, но сохранить расширение?

10

В Windows / DOS я могу сказать, rename myfile.* yourfile.*чтобы изменить имя, но сохранить расширение. Как это достигается в Linux?

Страница man предлагает только то, как изменить расширение, но это противоположно тому, что я хочу.

Бонус:
я действительно хочу поместить дату создания фотографии в имя файла, чтобы получить что-то вроде 20091231 2359 New Year.jpg. Боюсь, что мне нужна какая-то нетривиальная комбинация команд для достижения этого?

Торбен Гундтофте-Бруун
источник

Ответы:

14

Вот ответ на бонусный вопрос.

Я на самом деле хочу поместить дату создания фотографии в имя файла, чтобы получить что-то вроде 20091231 2359 New Year.jpg. Боюсь, что мне нужна какая-то нетривиальная комбинация команд для достижения этого?

Предполагая, что вы хотите взять дату создания фотографии из данных EXIF, вам понадобится отдельный инструмент для этого. К счастью, оказывается, что jheadпредлагает тривиальный способ сделать именно то, что вы хотите, с его -nопцией.

$ 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
             [...]

Вот пример:

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

Изменить : Конечно, чтобы сделать это для кучу фотографий, это было бы что-то вроде:

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

Чтобы настроить форматирование даты по своему вкусу, взгляните на вывод date --help, например; это перечислит доступные коды формата.

(jhead широко доступен для разных систем. Если вы, например, используете Ubuntu или Debian, просто введите его, sudo apt-get install jheadчтобы установить.)

Jonik
источник
1
Я не думал о jhead, только о безобразной комбинации переименования, stat и cut. Спасибо за отличный ответ!
Торбен Гундтофте-Брюн
10

Программа переименования будет работать только для части переименования. Это так же, как пример, который вы видели на странице руководства, только что переключился.

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$ 
user23307
источник
1
В некоторых дистрибутивах эта программа переименования perl называется prename.
Camh
Это действительно полезно! Я был удивлен тем, сколько вопросов такого типа мне пришлось искать, прежде чем найти «переименовать». Спасибо.
alanning
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

Ключевым моментом является то, что, если вы видели пример, который показывает, как обработать одну часть имени файла с помощью регулярного выражения, это единственный пример, который вам нужен. Расширения не имеют специального статуса в файловых системах Unix - они являются лишь частью имени файла, которое происходит после .символа.

Джеймс Полли
источник
1
Это ответ на мой вопрос. (Но другой ответ приводит меня туда быстрее и проще.)
Торбен Гундтофте-Брюн
4
Нет необходимости вилке + ехес не СЭД: mv "$file" yourfile"${file#myfile}". Работает на любой современной оболочке, похожей на Bourne (или на любую оболочку POSIX), но, вероятно, не на настоящую оболочку Bourne.
Крис Джонсен
4

Вот еще несколько различных способов манипулировать именами файлов

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

Расширения параметров в mvкоманде работают следующим образом:

${f%.*}- Удалить кратчайший соответствующий шаблон из конца строки, содержащейся в этом $f, в этом случае удалить все после и включая последнюю точку. Сингл %означает «самый короткий с конца».

${f##*.}- Удалить самый длинный соответствующий шаблон из начала строки, содержащейся $f, в этом случае все до и включая последнюю точку (включая все другие точки). Двойной #( ##) означает «самый длинный с самого начала».

Так, например, если $fсодержит «Foo.bar.baZ.jpg»:

echo "${f%.*}"

дает

Foo.bar.baZ

а также

echo "${f##*.}"

дает

jpg

Таким образом mv, однажды развернутая команда будет выглядеть так:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"
Приостановлено до дальнейшего уведомления.
источник
Я фактически закончил тем, что использовал цикл FOR, но не пример MV, потому что я не понимаю этого :-)
Торбен Гундтофте-Бруун
Примечание: значение тех f%и f##описано здесь, например: tldp.org/LDP/abs/html/parameter-substitution.html
Торбен Гундтофте-Брюн,
3

В Linux нет расширений файлов.

Используйте регулярные выражения, чтобы вырезать определенные подстроки из имени файла и получить к ним доступ.

Пример:

Реальный сценарий: вы извлекаете html из файла chm. Имена файлов в Windows нечувствительны к регистру, поэтому в Linux вы получите неработающие ссылки. У вас есть файл с именем index.HTML , но href = "index.html" в URL. Итак, ваша цель - адаптировать имена файлов, чтобы они соответствовали ссылкам на них.

Предположим, у вас есть имя файла в переменной:

FILENAME='index.HTML'

Начиная с версии 3.0, bash сама поддерживает регулярные выражения, поэтому вам не нужны никакие дополнительные инструменты, такие как grep / sed / perl и т. Д. Для выполнения операций со строками. В следующем примере показана замена внутреннего соответствия в строке:

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

Строки соответствия и замены могут быть параметризованы, если вы хотите, это обеспечивает дополнительную гибкость при написании скрипта. Следующий фрагмент кода достигает той же цели:

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

Консультируйтесь с документами bash для дополнительной информации.

фанат
источник
1
Любой пример этих регулярных выражений?
Gnoupi
+1. Этот ответ очень полезен сейчас (после редактирования) - я понятия не имел, что вы можете делать такие манипуляции со строками в Bash.
Джоник
Действительно, теперь намного лучше с примерами. +1
Gnoupi
0

Вот еще один:

find -name "*.jpg" -printf '"%p" "%h/%TY%Tm%Td %TH%TM %f"\n' | while read -r f
do
    eval "mv ${f}"
done
Приостановлено до дальнейшего уведомления.
источник
0

Всегда есть несколько способов сделать это. Я поставил следующий скрипт как / usr / local / bin / mrename.

Затем в сценарии, содержащем файлы фотографий, просто введите: mrename

Также в скрипте есть дополнительная закомментированная функция для масштабирования фотографий (используя ImageMagick).

Надеюсь, что это полезно для некоторых людей.

#!/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";

источник
0

Вы можете использовать -X/--keep-extensionопцию с rename(версия 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 доступно для Mac из Homebrew и для Linux из Linuxbrew (среди прочих вариантов установки, конечно).

Джон
источник