Cách xóa (1) khỏi tên tệp bằng lệnh find


13

Gần đây tôi đã chuyển đổi tất cả các tệp FLAC của mình sang tốc độ lấy mẫu thấp hơn 44,1 kHz và độ sâu bit là 24 bit (vì iPhone / iPod không hỗ trợ bất cứ điều gì ở trên) bằng cách sử dụng XLD trên Mac OS 10.7 (Lion) của tôi.

Mặc dù tôi đã bảo XLD ghi đè lên tất cả các tệp trước đó, XLD đã nối thêm vào (1)cuối tệp rất giống như từ

some_song.m4a

đến

some_song(1).m4a

Vì vậy, bây giờ tôi muốn xóa nó (1)khỏi tất cả các tệp FLAC tôi đã chuyển đổi.

Tôi biết tôi có thể đã sử dụng một số chương trình hoặc thậm chí là AppleScript để đổi tên các tệp, nhưng tôi muốn học bằng cách sử dụng dòng lệnh cũ của trường.

Tôi biết rằng find . -name *\(1\).m4asẽ lấy tất cả các tệp FLAC được chuyển đổi.

Tiếp theo tôi biết tôi phải làm một cái gì đó với -execmvđổi tên tất cả các tập tin tìm thấy. Nhưng những gì tôi không thể tìm ra là làm thế nào để giữ tên tệp gốc và chỉ xóa (1).

Có lẽ tôi cần phải thực hiện một số regex nhóm để lưu trữ phần tên tệp mà tôi không muốn sửa đổi? Hoặc có thể không thể thực hiện mọi thứ trong một dòng và tôi nên tạo một tập lệnh shell (điều mà tôi không thoải mái khi làm, nhưng tôi sẵn sàng thử nó).

Bất kỳ lời khuyên hoặc đề nghị đều được hoan nghênh! Cảm ơn!


5
Tại sao các downvote? Có vẻ như một câu hỏi hợp lệ ...

không liên quan đến câu hỏi cụ thể của bạn (trên find) nhưng điều đó có thể đang giải quyết vấn đề thực tế của bạn (chuyển đổi tệp âm thanh), bạn có thể quan tâm đến việc xem audiotools.sourceforge.net và trường hợp ví dụ này (đối với sư tử macosx) invibe.net/ LaurentPerrinet / SciBlog / 2012-04-22
meduz

Câu trả lời:


13

Đừng cố phân tích findđầu ra ngoại trừ như là phương sách cuối cùng. Điều quan trọng là phải nhận ra rằng trên các hệ thống tệp Unix, tên tệp không phải là chuỗi (một quan niệm sai lầm phổ biến) mà là các đốm nhị phân có thể chứa bất kỳ ký tự nào ngoại trừ /và ký tự null. Phân tích tên tệp một cách an toàn và chính xác là đủ đến nỗi 99% thời gian bạn sẽ chỉ muốn tránh làm điều đó hoàn toàn (chỉ cần nhìn vào cách sedbiểu hiện lông trong câu trả lời của @ yarek và thậm chí không bao gồm tất cả các trường hợp) . Rất may, trong trường hợp này có một cách tiếp cận đơn giản hơn nhiều:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+

cách tiếp cận gọn gàng nhưng nhiều lông như biểu hiện sed :) +1
yrk

1
cái gì đó còn thiếu ở đây ... ở đâu done?
yrk

@yarek Cảm ơn đã bắt. Sự khác biệt lớn nhất giữa sedphương pháp này và phương pháp đường ống là điều này an toàn hơn nhiều. Nó vẫn dễ đọc hơn súp backexash, với điều kiện bạn hiểu một số cấu trúc kịch bản shell cơ bản.
jw013

Bạn đúng; cái này sạch hơn nhiều Và các $argbiến làm cho nó dễ đọc hơn nhiều.
hobbes3

1
@DQdlM Đoạn mã tôi đã đăng ở trên chỉ được findgọi shvới cú pháp POSIX khá di động. Để biết thêm chi tiết, bạn có thể kiểm tra phần Parameter Expansion , các phần về lệnh hợp chất mà giải thích các forvòng lặp , và POSIX findđặc tả . Ngoài những tài nguyên đó, tôi rất sẵn lòng trả lời bất kỳ câu hỏi cụ thể nào bạn có.
jw013

6

Trên Debian và Ubuntu, tôi có thể sử dụng rename 's/\(1\)//' *.m4ađể giải quyết vấn đề của bạn.


Thật kỳ lạ, tôi có thể làm man rename, nhưng tôi thực sự không có rename: -bash: rename: command not found( which renamekhông hiển thị gì cả).
hobbes3

@ hobbes3 trên mac ở đây man -a renametìm thấy đổi tên (2) - tòa nhà và đổi tên (n) - lệnh TCL. Không có đổi tên (1) cũng như tiện ích ở đó.
yrk

1
IIRC, renamelà một tập lệnh perl có trong các ví dụ được bao gồm trong một số cài đặt perl và một vài distro bao gồm nó trong đường dẫn bởi vì đó là một lệnh thuận tiện. (@Hobbes có lẽ bạn có thể tìm thấy nó trên internet)
Kevin

@Kevin trên hệ thống của tôi renamelà nhị phân bình thường (không phải perl). Tuy nhiên, một cảnh báo khác là không phải tất cả các phiên bản của biểu thức renamehỗ trợ. Phiên bản tôi có ví dụ chỉ cho phép bạn làm thay thế chuỗi trực tiếp, ví dụrename '(1)' '' *.m4a
Patrick

1
renameKịch bản Perl chỉ được cài đặt bởi Debian và các dẫn xuất. Các hệ thống Linux khác có một renametiện ích khác (được hiển thị bởi Patrick). OSX không có.
Gilles 'SO- ngừng trở nên xấu xa'

4

Trong zsh, sử dụng zmv :

autoload zmv      # you can put this line in your .zshrc
zmv '(*)\(1\)(*)' '$1$2'

Trong đối số thứ hai (tên mới) $1$2tham khảo các nhóm được ngoặc (PATTERN)trong mẫu nguồn. Một cách khác để viết đổi tên này là

zmv '(*)' '${1/\(1\)/}'

3

Cách tiếp cận sau đây cung cấp cho bạn khả năng xem trước / lược bớt các lệnh được tạo trước khi thực hiện chúng và nó rất dễ mang theo: nó không chỉ hoạt động trên máy mac, không chỉ với bash và không chỉ với GNU sed; ngay cả trên các hệ thống không có findlệnh (1) cũng có thể thay thế nó bằng du(1) mà không gặp sự cố.

find . -name '*(1).m4a' |
sed 's/\(.*\)(1).m4a$/mv & \1.m4a/' 

Nếu hài lòng với các lệnh được in, hãy chạy lại với phần | sh -xbổ sung.

Nếu lo ngại về khoảng trắng trong tên tệp, hãy thêm s khác để thoát tất cả khoảng trắng:

find . -name '*(1).m4a' |
sed -e 's/ /\\ /g' -e 's/\(.*\)(1).m4a$/mv & \1.m4a/'

Nếu các ký tự đặc biệt khác được mong đợi, nó sẽ khó khăn hơn một chút:

find . -name '*(1).m4a' |
sed -e "s/'/'\\\\''/g" -e 's/\(.*\)(1).m4a$/mv '\''&'\'' '\''\1.m4a'\'/

Hàm đầu tiên chuyển đổi tất cả 'thành một dạng sao cho chúng được thực hiện theo đúng nghĩa đen khi ở giữa '...'chuỗi ký tự. Hàm thứ hai tạo ra các lệnh mv có đối số được đặt trong '...'.


1
Lệnh đó không thoát khỏi tên tệp (khoảng trắng (và tất cả các ký tự đặc biệt khác) hoặc thêm dấu ngoặc kép quanh tên tệp. Tôi đã thử sửa đổi lệnh của bạn, nhưng tôi không thể tìm ra cách thêm dấu ngoặc kép quanh cả tên tệp cho mvlệnh. Một trong những kết quả đầu ra từ lệnh của bạn là mv ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us(1).m4a ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us.m4a. Và nếu tôi chạy lệnh đó, tôi nhận được -bash: syntax error near unexpected token '('.
hobbes3

đây được coi là một bài tập về nhà :) nhưng ok, tôi sẽ cập nhật câu trả lời
yrk

Bằng cách này, GNU sed có thể tự thực thi lệnh bằng cách thêm elệnh sau khi thay thế. Ví dụ find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'sẽ thực hiện lệnh mà không cần đường ống đến sh -x.
vội vàng

@Rush đó là sed duy nhất làm điều đó; và dù sao nó cũng cần khởi động shell, nhưng một lệnh mới cho mỗi lệnh (nhắc nhở vấn đề tạo ra , phải không?)
yrk

2
Tôi không nghĩ rằng chúng ta nên hạ thấp. Đó là một giải pháp hợp lệ sau tất cả.
hobbes3

1

Đây là một đoạn script nhỏ thực hiện nó:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done

cái này sẽ bị sặc trên các tệp có khoảng trắng trong tên của chúng; cũng nó đòi hỏi đủ lưu trữ tạm thời lớn cho`find ...`
yrk
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.