Linux: ganti nama file tetapi pertahankan ekstensi?

10

Di Windows / DOS, saya bisa mengatakan rename myfile.* yourfile.*untuk mengubah nama tetapi mempertahankan ekstensi. Bagaimana itu dilakukan di Linux?

Halaman manual hanya menyarankan cara mengubah ekstensi, tapi itu kebalikan dari yang saya inginkan.

Bonus:
Saya sebenarnya ingin memasukkan tanggal pembuatan foto ke nama file, untuk mendapatkan sesuatu seperti 20091231 2359 New Year.jpg. Saya takut bahwa saya memerlukan kombinasi perintah yang tidak sepele untuk mencapai itu?

Torben Gundtofte-Bruun
sumber

Jawaban:

14

Inilah jawaban untuk pertanyaan bonus.

Saya sebenarnya ingin memasukkan tanggal pembuatan foto ke nama file, untuk mendapatkan sesuatu seperti 20091231 2359 New Year.jpg. Saya takut bahwa saya memerlukan kombinasi perintah yang tidak sepele untuk mencapai itu?

Dengan asumsi Anda ingin mengambil tanggal pembuatan foto dari data EXIF, Anda akan memerlukan alat terpisah untuk itu. Untungnya ternyata jheadmenawarkan cara sepele untuk melakukan apa yang Anda inginkan, dengan -npilihannya.

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

Ini sebuah contoh:

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

Sunting : Tentu saja, untuk melakukan ini untuk banyak foto, itu akan menjadi seperti:

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

Untuk mengubah format tanggal sesuai keinginan Anda, lihat output date --help, misalnya; itu akan mencantumkan kode format yang tersedia.

(jhead tersedia secara luas untuk sistem yang berbeda. Jika Anda mis. pada Ubuntu atau Debian, cukup ketik sudo apt-get install jheaduntuk menginstalnya.)

Jonik
sumber
1
Aku tidak memikirkan jhead, hanya kombinasi jelek dari penggantian nama, stat, dan cut. Terima kasih atas jawaban yang bagus!
Torben Gundtofte-Bruun
10

Untuk bagian penggantian nama saja, program 'ganti nama' akan berfungsi. Itu sama dengan contoh yang Anda lihat di halaman manual, baru saja diputar.

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$ 
pengguna23307
sumber
1
Pada beberapa distro, program perubahan nama perl ini disebut prename.
camh
Ini sangat berguna! Saya terkejut dengan banyaknya jenis pertanyaan yang harus saya selidiki sebelum menemukan "ganti nama". Terima kasih.
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

Kuncinya adalah bahwa, jika Anda telah melihat contoh yang menunjukkan bagaimana melakukan munge satu bagian dari nama file dengan regex, itulah satu-satunya contoh yang Anda butuhkan. Ekstensi tidak memiliki status khusus pada sistem file unix - mereka hanya bagian dari nama file yang terjadi setelah .karakter.

James Polley
sumber
1
Ini adalah jawaban untuk pertanyaan saya. (Tapi jawaban lain membuat saya di sana lebih cepat & lebih mudah.)
Torben Gundtofte-Bruun
4
Tidak perlu garpu + exec sed: mv "$file" yourfile"${file#myfile}". Bekerja pada shell seperti Bourne modern (atau shell POSIX), tetapi mungkin bukan shell Bourne yang sebenarnya.
Chris Johnsen
4

Berikut adalah beberapa cara berbeda untuk memanipulasi nama file

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

The parameter ekspansi dalam mvpekerjaan perintah sebagai berikut:

${f%.*}- Hapus pola pencocokan terpendek dari ujung string yang terkandung $f, dalam hal ini hapus semuanya setelah dan termasuk titik terakhir. Single ini %berarti "terpendek dari akhir".

${f##*.}- Hapus pola pencocokan terpanjang dari awal string yang terkandung $f, dalam hal ini semuanya sebelum dan termasuk titik terakhir (ini termasuk titik-titik lain juga). Dobel #( ##) berarti "terpanjang dari awal".

Jadi, misalnya, jika $fmengandung "Foo.bar.baZ.jpg":

echo "${f%.*}"

memberi

Foo.bar.baZ

dan

echo "${f##*.}"

memberi

jpg

Jadi mvperintah, setelah diperluas akan terlihat seperti:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"
Dijeda sampai pemberitahuan lebih lanjut.
sumber
Saya akhirnya menggunakan loop FOR tetapi bukan contoh MV karena saya tidak memahaminya :-)
Torben Gundtofte-Bruun
Catatan: Arti dari semua itu f%dan f##dijelaskan di sini, misalnya: tldp.org/LDP/abs/html/parameter-substitution.html
Torben Gundtofte-Bruun
3

Tidak ada ekstensi nama file di Linux.

Gunakan ekspresi reguler untuk memotong substring tertentu dari nama file dan mengaksesnya.

Contoh:

Skenario kehidupan nyata: Anda mengekstrak html dari file chm. Nama file di Windows peka huruf besar kecil, jadi di Linux Anda akan mendapatkan tautan yang rusak. Anda memiliki file bernama index.HTML , tetapi href = "index.html" di URL. Jadi tujuan Anda adalah mengadaptasi nama file agar sesuai dengan tautan ke sana.

Asumsikan Anda memiliki nama file dalam variabel:

FILENAME='index.HTML'

Dimulai dengan versi 3.0 bash mendukung ekspresi reguler itu sendiri, jadi Anda tidak memerlukan alat tambahan seperti grep / sed / perl dll untuk melakukan manipulasi string. Contoh berikut menggambarkan penggantian kecocokan back-end dalam sebuah string:

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

String kecocokan dan penggantian dapat diprioritaskan jika diinginkan, ini memberikan fleksibilitas tambahan saat menulis skrip. Cuplikan kode berikut mencapai tujuan yang sama:

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

Konsultasikan bash docs untuk info tambahan.

kutu buku
sumber
1
Adakah contoh, pada ekspresi reguler ini?
Gnoupi
+1. Jawaban ini sangat berguna sekarang (setelah diedit) - Saya tidak tahu Anda dapat melakukan manipulasi string seperti itu di Bash.
Jonik
Memang, jauh lebih baik sekarang, dengan contoh-contoh. +1
Gnoupi
0

Ini yang lain:

find -name "*.jpg" -printf '"%p" "%h/%TY%Tm%Td %TH%TM %f"\n' | while read -r f
do
    eval "mv ${f}"
done
Dijeda sampai pemberitahuan lebih lanjut.
sumber
0

Selalu ada lebih dari satu cara untuk melakukannya. Saya menempatkan skrip berikut sebagai / usr / local / bin / mrename.

Kemudian dalam skrip yang berisi file foto, ketikkan: mrename

Ada juga fitur komentar opsional dalam skrip untuk skala foto (menggunakan ImageMagick).

Semoga ini bermanfaat bagi sebagian orang.

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

sumber
0

Anda dapat menggunakan -X/--keep-extensionopsi ini dengan rename(versi 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 tersedia untuk Mac dari Homebrew dan untuk Linux dari Linuxbrew (di antara opsi instal lainnya tentu saja).

John
sumber