Câu trả lời:
Một cách di động (sẽ hoạt động trên mọi hệ thống tuân thủ POSIX):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
Trong bash4, bạn có thể sử dụng globalstar để nhận được các thông số đệ quy (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Lệnh (perl) rename
trong Ubuntu có thể đổi tên các tệp bằng cú pháp biểu thức chính quy perl, mà bạn có thể kết hợp với globalstar hoặc find
:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
Đồng thời xem http://mywiki.wooledge.org/BashFAQ/030
${1%.abc}...
sh -c
đối số đầu tiên được gán cho $ 0 và mọi đối số còn lại được gán cho các tham số vị trí . Vì vậy, _
đối số giả là và '{}' là đối số vị trí đầu tiên sh -c
.
Điều này sẽ thực hiện nhiệm vụ được yêu cầu nếu tất cả các tệp trong cùng một thư mục
rename 's/.abc$/.edefg/' *.abc
Để đổi tên các tệp đệ quy sử dụng này:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abc
trong một phiên bản hiện đại của Bash.
s
lúc ban đầu, và những lựa chọn khác tôi có thể sử dụng trong đó. Cảm ơn !
Một vấn đề với việc đổi tên đệ quy là bất kỳ phương thức nào bạn sử dụng để định vị các tệp, nó đều chuyển toàn bộ đường dẫn tới rename
, không chỉ tên tệp. Điều đó làm cho việc đổi tên phức tạp trong các thư mục lồng nhau trở nên khó khăn.
Tôi sử dụng hành động find
của mình -execdir
để giải quyết vấn đề này. Nếu bạn sử dụng -execdir
thay vì -exec
, lệnh được chỉ định sẽ được chạy từ thư mục con chứa tệp phù hợp. Vì vậy, thay vì vượt qua toàn bộ con đường đến rename
, nó chỉ đi qua ./filename
. Điều đó làm cho nó dễ dàng hơn để viết regex.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
Chi tiết:
-type f
có nghĩa là chỉ tìm tập tin, không phải thư mục-name '*.abc'
có nghĩa là chỉ khớp tên tệp kết thúc bằng .abc'{}'
là trình giữ chỗ đánh dấu nơi -execdir
sẽ chèn đường dẫn tìm thấy. Các dấu ngoặc đơn là bắt buộc, để cho phép nó xử lý tên tệp có dấu cách và ký tự shell.-type
và -name
là ký tự tiếp tục dòng bash. Tôi sử dụng chúng để làm cho ví dụ này dễ đọc hơn, nhưng chúng không cần thiết nếu bạn đặt tất cả lệnh của mình trên một dòng.-execdir
dòng là bắt buộc. Nó ở đó để thoát dấu chấm phẩy, chấm dứt lệnh chạy bởi -execdir
. Vui vẻ!Giải thích về regex:
s/
bắt đầu của regex\.\/
phù hợp với hàng đầu ./ mà -execdir đi vào. Sử dụng \ để thoát. và / metachar character (lưu ý: phần này thay đổi tùy theo phiên bản của bạn find
. Xem bình luận từ người dùng @apollo)(.+)
khớp với tên tệp. Các dấu ngoặc đơn nắm bắt trận đấu để sử dụng sau\.abc
thoát khỏi dấu chấm, khớp với abc$
neo trận đấu ở cuối chuỗi
/
đánh dấu sự kết thúc của phần "khớp" của biểu thức chính quy và phần bắt đầu của phần "thay thế"
version1_
thêm văn bản này vào mỗi tên tập tin
$1
tham chiếu tên tệp hiện có, bởi vì chúng tôi đã bắt nó bằng dấu ngoặc đơn. Nếu bạn sử dụng nhiều bộ dấu ngoặc trong phần "khớp", bạn có thể tham khảo chúng ở đây bằng cách sử dụng $ 2, $ 3, v.v..abc
tên tệp mới sẽ kết thúc bằng .abc. Không cần phải thoát vi khuẩn chấm ở đây trong phần "thay thế"/
kết thúc của regexTrước
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Sau
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Gợi ý: rename
's -n tùy chọn là hữu ích. Nó chạy khô và cho bạn biết tên nó sẽ thay đổi, nhưng không thực hiện bất kỳ thay đổi nào.
--execdir
không vượt qua trong phần dẫn đầu ./
để \.\/
phần trong regex có thể được bỏ qua. May mà là vì tôi là trên OSX không ubuntu
Một cách di động khác:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Cũng xem mục tại sao bạn không nên phân tích cú pháp ls
.
Chỉnh sửa: nếu bạn phải sử dụng tên cơ sở, cú pháp của bạn sẽ là:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-mult Môn-files
Đây là những gì tôi đã làm và làm việc khá theo cách tôi muốn. Tôi đã sử dụng mv
lệnh. Tôi có nhiều .3gp
tệp và tôi muốn đổi tên tất cả thành.mp4
Đây là một oneliner ngắn cho nó:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Mà chỉ cần quét qua thư mục hiện tại, chọn tất cả các tệp .3gp, sau đó đổi tên (sử dụng mv) thành ren-name_of_file.mp4
file.3gp
thành file.3gp.mp4
, đó có thể không phải là điều mà hầu hết mọi người muốn.
.3gp
hoặc .mp4
ở đây chỉ là cho mục đích minh họa.
basename "$i" .mp4
để xóa tiện ích mở rộng trước đó thay vì "ren- $ i.mp4".
Tôi sẽ sử dụng lệnh mmv từ gói cùng tên :
mmv ';*.abc' '#1#2.edefg'
Các ;
trận đấu bằng 0 hoặc nhiều hơn */
và tương ứng với #1
trong thay thế. Các *
tương ứng với #2
. Phiên bản không đệ quy sẽ là
mmv '*.abc' '#1.edefg'
Đổi tên tập tin và thư mục với find -execdir | rename
Nếu bạn định đổi tên cả tệp và thư mục không chỉ đơn giản bằng hậu tố, thì đây là một mẫu tốt:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find . -depth -execdir rename 's/findme/replaceme/' '{}' \;
-execdir
Tùy chọn tuyệt vời thực hiện một cd
vào thư mục trước khi thực hiện rename
lệnh, không giống như -exec
.
-depth
đảm bảo rằng việc đổi tên xảy ra trước tiên đối với trẻ em và sau đó là cha mẹ để ngăn ngừa các vấn đề tiềm ẩn với các thư mục cha mẹ bị thiếu.
-execdir
là bắt buộc vì đổi tên không chơi tốt với các đường dẫn đầu vào không phải là tên cơ sở, ví dụ như các lỗi sau:
rename 's/findme/replaceme/g' acc/acc
Việc PATH
hack là bắt buộc vì -execdir
có một nhược điểm rất khó chịu: find
cực kỳ quan tâm và từ chối làm bất cứ điều gì -execdir
nếu bạn có bất kỳ đường dẫn tương đối nào trong PATH
biến môi trường của mình , ví dụ: ./node_modules/.bin
thất bại với:
find: Đường dẫn tương đối './node_modules/.bin' được bao gồm trong biến môi trường PATH, không an toàn khi kết hợp với hành động -execdir của find. Vui lòng xóa mục nhập đó khỏi $ PATH
Xem thêm: Tại sao sử dụng hành động '-execdir' không an toàn cho thư mục nằm trong PATH?
-execdir
là một phần mở rộng tìm GNU cho POSIX . rename
là dựa trên Perl và đến từ rename
gói. Đã thử nghiệm trong Ubuntu 18.10.
Đổi tên cách nhìn
Nếu đường dẫn đầu vào của bạn không xuất phát find
hoặc nếu bạn đã có đủ sự khó chịu của đường dẫn tương đối, chúng ta có thể sử dụng một số giao diện Perl để đổi tên thư mục một cách an toàn như trong:
git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
Tôi đã không tìm thấy một chất tương tự thuận tiện cho việc -execdir
với xargs
: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
Các sort -r
yêu cầu để đảm bảo rằng các tập tin đến sau khi các thư mục tương ứng của họ, kể từ khi con đường còn đi sau những ngắn hơn với tiền tố giống nhau.