Linux: переименовать файл, но сохранить расширение?
В Windows/DOS могу сказать rename myfile.* yourfile.*
изменить имя, но сохранить расширение. Как это достигается в Linux?
Страница man предлагает только то, как изменить расширение, но это противоположно тому, что я хочу.
Бонус:
Я на самом деле хочу поместить дату создания фотографии в ее имя файла, чтобы получить что-то вроде 20091231 2359 New Year.jpg
, Боюсь, что мне нужна какая-то нетривиальная комбинация команд для достижения этого?
10 ответов
Вот ответ на бонусный вопрос.
Я на самом деле хочу поместить дату создания фотографии в ее имя, чтобы получить что-то вроде 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
установить его.)
Программа переименования будет работать только для части переименования. Это так же, как пример, который вы видели на странице руководства, только что переключился.
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$
Вот еще пара различных способов манипулирования именами файлов
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"
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 - они являются лишь частью имени файла, которое происходит после .
персонаж.
В 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 для получения дополнительной информации.
Всегда есть несколько способов сделать это. Я поставил следующий скрипт как /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";
Если другой ответ с использованием этой команды вам не помог, попробуйте следующее:
touch myfile.txt
rename -v myfile yourfile myfile.*
The -v
флаг не обязателен. Он просто включает подробную опцию, которая сообщает вам, какие действия он предпринимает.
Переименование версий
Другой ответ предполагает, что вы используете версию изperl
упаковка. Эта версия доступна только в некоторых дистрибутивах. Ответ здесь предполагает, что вы используетеrename
команда изutil-linux
упаковка. Эта команда доступна практически во всех дистрибутивах (хотя название может быть другим).
Дополнительную информацию см. в этом ответе:https://unix.stackexchange.com/questions/730894/what-are-the- Different-versions-of-the-rename-command-how-do-i-use-the-perl -вер
Вы можете использовать -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 (среди прочих вариантов установки, конечно).
Я не понял, как использовать пример переименования. Однако я написал свой собственный bash-скрипт, который принимает исходное имя файла с его расширением и новое имя без расширения:
# trans_file_extension:
# transfers the file extension from path_file to new_path_no_extension
# and returns both
#!/bin/bash
path_file=$1
new_path_no_extension=$2
dir_name=$(dirname $path_file)
base_name=$(basename $path_file)
name_without_extension="${base_name%%.*}"
extension="${base_name#*.}"
path_copy=$new_path_no_extension"."$extension
echo $path_file $path_copy
Затем вы можете использовать его для перемещения или копирования через:
mv `./trans_file_extension tmp.json tmp_copy`
cp `./trans_file_extension tmp.json tmp_copy`
Вот еще один:
find -name "*.jpg" -printf '"%p" "%h/%TY%Tm%Td %TH%TM %f"\n' | while read -r f
do
eval "mv ${f}"
done