Linux: เปลี่ยนชื่อไฟล์ แต่ให้นามสกุล?


10

ใน Windows / DOS ฉันสามารถพูดrename myfile.* yourfile.*เพื่อเปลี่ยนชื่อได้ แต่เก็บนามสกุลไว้ สิ่งนั้นสำเร็จบน Linux ได้อย่างไร?

หน้าคนแนะนำวิธีการเปลี่ยนนามสกุล แต่นั่นคือสิ่งที่ตรงกันข้ามกับที่ฉันต้องการ

โบนัส: ที่จริงผมต้องการที่จะนำวันที่สร้างภาพให้เป็นชื่อไฟล์เพื่อให้ได้สิ่งที่ต้องการ
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
ฉันไม่เคยนึกถึงหัวกระโหลกเพียงแค่การเปลี่ยนชื่อน่าเกลียดสถิติและการตัด ขอบคุณสำหรับคำตอบที่ยอดเยี่ยม!
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
ในบาง distros โปรแกรมเปลี่ยนชื่อ 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

ที่สำคัญคือถ้าคุณเห็นตัวอย่างที่แสดงวิธีการลบส่วนหนึ่งของชื่อไฟล์ด้วย regex นั่นเป็นเพียงตัวอย่างเดียวที่คุณต้องการ ส่วนขยายไม่มีสถานะพิเศษในระบบไฟล์ยูนิกซ์ - เป็นเพียงส่วนหนึ่งของชื่อไฟล์ที่เกิดขึ้นหลังจาก.ตัวละคร


1
นี่คือคำตอบสำหรับคำถามของฉัน (แต่คำตอบอื่นทำให้ฉันเร็วขึ้นและง่ายขึ้น)
Torben Gundtofte-Bruun

4
ไม่จำเป็นต้องส้อม + exec mv "$file" yourfile"${file#myfile}"sed: ทำงานบนเชลล์แบบบอร์นที่ทันสมัย ​​(หรือ POSIX เชลล์) ใด ๆ แต่อาจไม่ใช่เชลล์บอร์นจริง
Chris Johnsen

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ในกรณีนี้ทุกอย่างก่อนและรวมถึงจุดสุดท้าย (รวมถึงจุดอื่น ๆ เช่นกัน) double #( ##) หมายถึง "ยาวที่สุดตั้งแต่ต้น"

ตัวอย่างเช่นหาก$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"

ฉันลงเอยด้วยการใช้วงวนจริง แต่ไม่ใช่ตัวอย่าง MV เพราะฉันไม่เข้าใจ :-)
Torben Gundtofte-Bruun

หมายเหตุ: ความหมายของสิ่งเหล่านั้นf%และf##อธิบายไว้ที่นี่ตัวอย่างเช่น: tldp.org/LDP/abs/html/parameter-substitution.html
Torben

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}

สตริงการจับคู่และการแทนที่สามารถ parametrized หากคุณต้องการสิ่งนี้ให้ความยืดหยุ่นเพิ่มเติมเมื่อเขียนสคริปต์ ข้อมูลโค้ดต่อไปนี้บรรลุเป้าหมายเดียวกัน:

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

ศึกษา bash docs สำหรับข้อมูลเพิ่มเติม


1
ตัวอย่างใดในนิพจน์ทั่วไปเหล่านี้
Gnoupi

+1 คำตอบนี้มีประโยชน์มากในตอนนี้ (หลังจากแก้ไข) - ฉันไม่รู้ว่าคุณสามารถจัดการสตริงดังกล่าวใน Bash ได้
Jonik

แท้จริงตอนนี้มีตัวอย่างที่ดีกว่ามาก +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 (รวมถึงตัวเลือกการติดตั้งอื่น ๆ )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.