Linux: đổi tên tập tin nhưng giữ phần mở rộng?


10

Trong Windows / DOS, tôi có thể nói rename myfile.* yourfile.*thay đổi tên nhưng vẫn giữ phần mở rộng. Làm thế nào là hoàn thành trên Linux?

Trang hướng dẫn chỉ đề xuất cách thay đổi tiện ích mở rộng, nhưng điều đó ngược lại với những gì tôi muốn.

Phần thưởng:
Tôi thực sự muốn đặt ngày tạo của ảnh vào tên tệp của nó, để có được một cái gì đó như thế 20091231 2359 New Year.jpg. Tôi sợ rằng tôi cần một số lệnh kết hợp không tầm thường để đạt được điều đó?

Câu trả lời:


14

Đây là một câu trả lời cho câu hỏi tiền thưởng.

Tôi thực sự muốn đặt ngày tạo của ảnh vào tên tệp của nó, để có được một cái gì đó như 20091231 2359 New Year.jpg. Tôi sợ rằng tôi cần một số lệnh kết hợp không tầm thường để đạt được điều đó?

Giả sử bạn muốn lấy ngày tạo ảnh từ dữ liệu EXIF, bạn sẽ cần một công cụ riêng cho việc đó. May mắn thay, nó jheadcung cấp một cách tầm thường để làm chính xác những gì bạn muốn, với -ntùy chọn của 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
             [...]

Đây là một ví dụ:

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

Chỉnh sửa : Tất nhiên, để làm điều này cho một loạt ảnh, nó sẽ giống như:

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

Để điều chỉnh định dạng ngày theo ý thích của bạn date --help, ví dụ , hãy xem đầu ra của ; nó sẽ liệt kê các mã định dạng có sẵn.

(jhead có sẵn rộng rãi cho các hệ thống khác nhau. Nếu bạn là ví dụ trên Ubuntu hoặc Debian, chỉ cần gõ sudo apt-get install jheadđể cài đặt nó.)


1
Tôi đã không nghĩ về jhead, chỉ có một sự kết hợp xấu xí của đổi tên, stat và cắt. Cảm ơn bạn đã trả lời tuyệt vời!
Torben Gundtofte-Bruun

10

Đối với chỉ phần đổi tên, chương trình 'đổi tên' sẽ hoạt động. Nó giống như ví dụ bạn đã thấy trong trang man, chỉ cần quay lại.

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
Trên một số distro, chương trình đổi tên perl này được gọi là prename.
camh

Điều này thực sự hữu ích! Tôi đã rất ngạc nhiên bởi có bao nhiêu loại câu hỏi mà tôi phải tìm kiếm trước khi tìm thấy "đổi tên". Cảm ơn bạn.
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

Điều quan trọng là, nếu bạn đã xem một ví dụ cho thấy cách chuyển một phần của tên tệp bằng biểu thức chính, đó là ví dụ duy nhất bạn cần. Các tiện ích mở rộng không có trạng thái đặc biệt trên các hệ thống tập tin unix - chúng chỉ là một phần của tên tệp xảy ra sau một .ký tự.


1
Đây là câu trả lời cho câu hỏi của tôi. (Nhưng câu trả lời khác đưa tôi đến đó nhanh hơn & dễ dàng hơn.)
Torben Gundtofte-Bruun

4
Không cần fork + exec sed : mv "$file" yourfile"${file#myfile}". Hoạt động trên mọi vỏ giống như Bourne hiện đại (hoặc bất kỳ vỏ POSIX nào), nhưng có lẽ không phải là vỏ Bourne thực tế.
Chris Johnsen

4

Dưới đây là một vài cách khác nhau để thao tác tên tập tin

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

Các tham số mở rộng trong mvlệnh hoạt động như sau:

${f%.*}- Xóa mẫu phù hợp ngắn nhất từ ​​cuối chuỗi có trong $f, trong trường hợp này xóa mọi thứ sau và kể cả dấu chấm cuối cùng. Đĩa đơn %có nghĩa là "ngắn nhất từ ​​cuối".

${f##*.}- Xóa mẫu phù hợp dài nhất từ ​​đầu chuỗi có trong $f, trong trường hợp này là mọi thứ trước và kể cả dấu chấm cuối cùng (bao gồm cả các dấu chấm khác nữa). Double #( ##) có nghĩa là "dài nhất từ ​​đầu".

Vì vậy, ví dụ: nếu $fchứa "Foo.bar.baZ.jpg":

echo "${f%.*}"

cho

Foo.bar.baZ

echo "${f##*.}"

cho

jpg

Vì vậy, mvlệnh, một khi được mở rộng sẽ trông như sau:

mv "Foo.bar.baZ.jpg" "before_partFoo.bar.baZafter_part.jpg"

Tôi thực sự đã kết thúc bằng cách sử dụng vòng lặp FOR nhưng không phải là ví dụ MV vì tôi không hiểu nó :-)
Torben Gundtofte-Bruun

Lưu ý: Ý nghĩa của những thứ đó f%f##được mô tả ở đây, ví dụ: tldp.org/LDP/abs/html/parameter-substlation.html
Torben Gundtofte-Bruun

3

Không có phần mở rộng tên tệp trong Linux.

Sử dụng các biểu thức thông thường để cắt các chuỗi con cụ thể từ tên tệp và truy cập chúng.

Thí dụ:

Kịch bản thực tế: bạn đang trích xuất html từ tệp chm. Tên tệp trong Windows không phân biệt chữ hoa chữ thường, vì vậy trong Linux, bạn sẽ nhận được các liên kết bị hỏng. Bạn có một tệp có tên index.HTML , but href = "index.html" trong URL. Vì vậy, mục tiêu của bạn là điều chỉnh tên tệp để khớp với các liên kết đến chúng.

Giả sử bạn có tên tệp trong một biến:

FILENAME='index.HTML'

Bắt đầu với bash phiên bản 3.0 hỗ trợ chính các biểu thức chính quy, vì vậy bạn không cần bất kỳ công cụ bổ sung nào như grep / sed / perl, v.v. để thực hiện thao tác chuỗi. Ví dụ sau minh họa việc thay thế kết thúc khớp trong chuỗi:

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

Các chuỗi khớp và thay thế có thể được tham số hóa nếu bạn muốn, điều này cung cấp thêm tính linh hoạt khi viết tập lệnh. Đoạn mã sau đạt được cùng một mục tiêu:

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

Tham khảo tài liệu bash để biết thêm thông tin.


1
Bất kỳ ví dụ, trên các biểu thức thông thường?
Gnoupi

+1. Câu trả lời này rất hữu ích bây giờ (sau khi chỉnh sửa) - Tôi không biết bạn có thể thực hiện thao tác chuỗi như vậy trong Bash.
Jonik

Thật vậy, tốt hơn nhiều bây giờ, với các ví dụ. +1
Gnoupi


0

Luôn luôn có nhiều hơn một cách để làm điều đó. Tôi đặt đoạn script sau là / usr / local / bin / mrename.

Sau đó, trong tập lệnh chứa các tệp ảnh, chỉ cần gõ: mrename

Ngoài ra còn có một tính năng nhận xét tùy chọn trong tập lệnh để chia tỷ lệ ảnh (sử dụng ImageMagick).

Hy vọng điều này hữu ích cho một số người.

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

Bạn có thể sử dụng -X/--keep-extensiontùy chọn với rename(phiên bản 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 có sẵn cho Mac từ Homebrew và cho Linux từ Linuxbrew (trong số các tùy chọn cài đặt khác).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.