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для встановлення.)


1
Я не думав про jhead, лише про потворне поєднання перейменування, stat і cut. Дякую за чудову відповідь!
Torben Gundtofte-Bruun

10

Щойно перейменування, буде працювати програма «перейменування». Це те саме, що приклад, який ви бачили на сторінці man, щойно переключився.

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$ 

1
У деяких дистрибутивах ця програма перейменування perl називається prename.
camh

Це справді корисно! Мене здивувало, скільки таких запитань мені довелося шукати, перш ніж знайти "перейменувати". Дякую.
аланування

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
Це відповідь на моє запитання. (Але інша відповідь отримує мене там швидше і простіше.)
Torben Gundtofte-Bruun

4
Не потрібно fork + exec sed : 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, але не приклад МВ, тому що я цього не розумію :-)
Torben Gundtofte-Bruun

Примітка. Значення цих f%і f##описано тут, наприклад: tldp.org/LDP/abs/html/parameter-substitution.html
Torben Gundtofte-Bruun

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

Завжди існує більше ніж один спосіб зробити це. Я ставлю такий сценарій як / 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 (серед інших варіантів встановлення, звичайно).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.