Đổi tên nhiều tệp với mv để thay đổi phần mở rộng


27

Tôi muốn đổi tên các tập tin để thay đổi phần mở rộng của chúng, tìm cách thực hiện một cách hiệu quả

mv *.txt *.tsv

Nhưng khi làm điều này tôi nhận được:

* .tsv không phải là một thư mục

Tôi thấy hơi lạ khi 10 chương trình truy cập google đầu tiên mvnên hoạt động như thế này.


Bạn nên giải thích chính xác cách bạn muốn đổi tên các tệp đó.
Toto

1
Chà, tôi có các tệp có phần mở rộng là * .gappedPeak và muốn đổi tên chúng thành * .bed. tất cả chúng đều nằm trong cùng một thư mục nên rất đơn giản nhưng tôi cần một vòng lặp đầy đủ để thành công
Sander Van der Zeeuw

Những gì bạn tìm thấy trên Google áp dụng cho MSDOS tôi nghĩ.
tiktak

Giải pháp thay thế của @devnull thực sự hữu ích
lucasvw

Câu trả lời:


22

Khi bạn ban hành lệnh:

mv *.txt *.tsv

shell, giả sử bash, mở rộng các ký tự đại diện nếu có bất kỳ tệp phù hợp (bao gồm các thư mục). Danh sách các tập tin được chuyển đến chương trình, ở đây mv. Nếu không tìm thấy kết quả trùng khớp, phiên bản chưa được mở rộng sẽ được thông qua.

Một lần nữa: shell mở rộng các mẫu, không phải chương trình.


Tải các ví dụ có lẽ là cách tốt nhất, vì vậy chúng tôi đi đây:

Ví dụ 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Bây giờ những gì xảy ra trên mvdòng là shell mở rộng *.txtđến các tệp phù hợp. Vì không có *.tsvtập tin nào không thay đổi.

Các mvlệnh được gọi với hai đối số đặc biệt :

  • argc: Số lượng đối số, bao gồm cả chương trình.
  • argv: Một mảng các đối số, bao gồm chương trình là mục nhập đầu tiên.

Trong ví dụ trên đó sẽ là:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

Các mvkiểm tra chương trình để xem nếu đối số cuối cùng, *.tsvlà một thư mục. Vì không phải vậy, chương trình không thể tiếp tục vì nó không được thiết kế để nối các tệp. (Thường di chuyển tất cả các tệp thành một.) Cũng không tạo thư mục theo ý thích.

Kết quả là nó hủy bỏ và báo cáo lỗi:

mv: target ‘*.tsv’ is not a directory

Ví dụ 2:

Bây giờ nếu bạn nói:

$ mv *1.txt *.tsv

Các mvlệnh được thực thi với:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

Bây giờ, một lần nữa, mvkiểm tra xem nếu *.tsvtồn tại. Vì nó không phải là tập tin file1.txtđược chuyển đến *.tsv. Đó là: tập tin được đổi tên thành *.tsvdấu hoa thị và tất cả.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Ví dụ 3:

Nếu bạn nói:

$ mkdir *.tsv
$ mv *.txt *.tsv

Các mvlệnh được thực thi với:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

*.tsvbây giờ là một thư mục, các tập tin cuối cùng được chuyển đến đó.


Bây giờ: sử dụng các lệnh như some_command *.tsvkhi có ý định thực sự giữ ký tự đại diện, người ta phải luôn trích dẫn nó. Bằng cách trích dẫn, bạn ngăn các ký tự đại diện được mở rộng nếu có bất kỳ trận đấu nào. Ví dụ nói mkdir "*.tsv".

Ví dụ 4:

Việc mở rộng có thể được xem thêm nếu bạn làm ví dụ:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Ví dụ 5:

Bây giờ: mvlệnh có thể và thực hiện công việc trên nhiều tệp. Nhưng nếu có nhiều thì hai cái cuối cùng phải là một thư mục đích. (Tùy chọn bạn có thể sử dụng -t TARGET_DIRtùy chọn, ít nhất là cho GNU mv.)

Vì vậy, điều này là OK:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Ở đây mvsẽ được gọi với:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

và tất cả các tập tin kết thúc trong thư mục foo.


Đối với các liên kết của bạn. Bạn đã cung cấp một (trong một bình luận), nơi mvkhông được đề cập ở tất cả, nhưng rename. Nếu bạn có nhiều liên kết hơn, bạn có thể chia sẻ. Cũng như cho các trang người đàn ông nơi bạn tuyên bố điều này được thể hiện.


30

Tôi biết điều này không trả lời câu hỏi của bạn, nhưng trong trường hợp bạn đang tìm kiếm một cách khác để đổi tên các tệp so với vòng lặp công việc của bạn, tại sao không sử dụng find? Tôi đã sử dụng lệnh này nhiều lần để thay thế các phần mở rộng tệp trong các thư mục lớn với hàng trăm ngàn tệp trong đó. Điều này sẽ hoạt động trên mọi hệ thống tuân thủ POSIX:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Sự cố lệnh:

  1. ' .' => đường dẫn tìm kiếm bắt đầu từ thư mục hiện tại được đánh dấu bởi '. '

  2. -name=> đặt tìm tên trùng khớp (trong trường hợp này là tất cả các tệp kết thúc bằng .gappedPeak)

  3. -exec => thực hiện lệnh sau trên mỗi trận đấu

  4. sh -c => 'exec' tạo môi trường shell độc lập cho mỗi trận đấu

  5. mv "$1" "${1%.gappedPeak}.bed"=> mvbiến đầu tiên (ký hiệu là $ 1 ), là tên tệp hiện tại, thành tên mới. Ở đây tôi làm một chuỗi con phù hợp và xóa; vì vậy hãy lấy var đầu tiên một lần nữa, $ 1 và sử dụng %để xóa .gappedPeakkhỏi chuỗi. Các .bedcuối cùng chỉ concatenates biến còn lại, mà bây giờ chỉ , với , tạo mới filename.test#.bedtest#.bed

  6. Gạch dưới là một giữ chỗ cho $ 0

  7. Tên {}được thay thế bởi mỗi *.gappedPeaktên tệp ( ) được tìm thấy bởi findlệnh và trở thành $ 1 cho shlệnh.

  8. \;đánh dấu sự kết thúc của -execlệnh Bạn cũng có thể sử dụng ';'hoặc ";".

Thí dụ:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed

Bạn có thể đi qua lệnh mô tả những gì từng phần không?
dùng1717828

Tôi xin lỗi về điều đó, tôi đã cập nhật bài viết của mình. Mong rằng sẽ giúp.
devnull

1
Thật sự cảm ơn! Với một hướng dẫn bash và lời giải thích của bạn, tôi đã có thể có được mọi thứ.
dùng1717828

Không vấn đề gì. Vui vì nó giúp.
ngớ ngẩn

Hoạt động như một lá bùa. Dưới đây là một ví dụ đơn giản hóa khác cho file.abc-> blub.xyztrong nhiều thư mục con:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn

9

mv *.txt *.tsvkhông hoạt động; mvchỉ có thể đổi tên một tệp tại một thời điểm. Bạn đã hiểu sai hoặc giải thích hoặc họ sai.

mmvrenamecó thể đổi tên một số tệp cùng một lúc. Nhưng có hai phiên bản renamexung quanh được gọi là khác nhau. Có rất nhiều câu hỏi về điều đó ở đây.


1
cyberciti.biz/tips/... Các hit đầu tiên trên google đang nói rằng mv nên hoạt động như thats cũng do tại sao tôi thấy nó rất lạ
Sander Van der Zeeuw

3
@SanderVanderZeeuw Tôi không biết bạn đọc gì ở đó. Các ví dụ sử dụng rename, không mv.
Hauke ​​Laging

1
xin lỗi tôi đã dán sai HTML. Đây là một udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw

3
@SanderVanderZeeuw Xấu hổ. Những người này cung cấp các khóa học? Thật không may, tôi không thấy một khả năng liên lạc ở đó. Bạn có thể dễ dàng kiểm tra xem điều này có hoạt động không. Nhưng trong mv *.txt *.tsv mv(thường) không nhìn thấy *.txthoặc *.tsvngoại trừ tên tệp được mở rộng shell. Số lượng tệp mà các ký tự đại diện này mở rộng sẽ là "ngẫu nhiên". Tình huống duy nhất mà điều này hoạt động là nếu có một tệp có tên *.txtsẽ được đổi tên thành (theo nghĩa đen) *.tsv(không trích dẫn bashtùy chọn nullglobkhông được đặt).
Hauke ​​Laging 27/1/2015

1
Hoặc tồi tệ hơn. Nếu ai có một file có tên ví dụ foo.txtmột tên baz.tsvngười mv *.txt *.tsvsẽ ghi đè lên hiện .tsvtập tin ...
Runium

4

Ví dụ, nếu bạn có asd.txtqwe.txtcác tệp trong thư mục khi bạn chạy lệnh mv *.txt *.tsv, nó sẽ cố gắng di chuyển hai tệp này vào một thư mục có tên *.tsv. Bởi vì không có thư mục như vậy, nó đưa ra một lỗi.


Cảm ơn, điều này làm rõ một phần. Tuy nhiên, tôi thấy lạ là tôi thấy rất nhiều trang thủ công nơi họ tuyên bố mv nên hoạt động trên nhiều trang.
Sander Van der Zeeuw

2

rename(1)

renamelà một kịch bản perl của Larry Wall, nhà sản xuất perl. Nó lấy một biểu thức chính tả Perl và hoạt động trên tên tệp.

rename 's/\.txt$/.tsv/' *.txt

Cài đặt

Debian / Ubuntu

Nếu bạn cần cài đặt renametrên Debian / Ubuntu, bạn có thể làm

sudo apt install rename

0

Một lựa chọn khác để xem xét là sử dụng:

cp -p *.txt *.tsv
rm -f *.txt
  • Dòng đầu tiên sao chép tất cả *.txtcác tệp vào *.tsvtrong khi bảo quản các thuộc tính của chúng bằng -pcờ.
  • Dòng thứ hai loại bỏ tất cả các tệp với mẫu *.txt
  • Phương pháp này yêu cầu bạn có đủ dung lượng đĩa để tạm thời giữ cả tệp nguồn và tệp đích
  • Phương pháp này chậm hơn so với mvviệc chỉ thay đổi tên / thư mục / tên tệp mà không thực sự di chuyển các tệp trừ khi chúng nằm trên một phân vùng 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.