Làm cách nào tôi có thể sử dụng đổi tên để đổi tên đệ quy mỗi lần thành chữ hoa


11

Tôi muốn đổi tên đệ quy tất cả các tệp và thư mục (thư mục con) thành chữ hoa.

Tôi đã tìm thấy một số tập lệnh sẽ thực hiện nó để viết thường, nhưng tôi không biết làm thế nào để thay đổi chúng để nó sẽ làm theo cách khác (từ thấp đến trên).

Kịch bản mà tôi tìm thấy và hoạt động cho chữ thường, nhưng tôi không biết cách sửa đổi là:

rename 'y/A-Z/a-z/' *

Nó đến từ man rename.


Không biết gì về lệnh đổi tên, tôi nghi ngờ rằng nếu bạn thử rename 'y/a-z/A-Z/' *bạn sẽ có được thứ bạn muốn. Cẩn thận nơi bạn kiểm tra nó thông qua.
Warwick

nó không lặp lại (vì cái ban đầu không ...) nhưng nó hoạt động. Tôi không thể hiểu tại sao tôi không nghĩ về điều đó :), vậy thì!
jnhghy - Alexandru Jantea

Tôi nghĩ rằng với chất lượng câu trả lời của Gilles, nó sẽ tốt hơn nếu bạn chấp nhận câu trả lời của anh ấy theo sở thích của tôi. Nó hoàn thiện hơn nhiều so với của tôi và giải thích các tùy chọn của bạn (và cách tất cả hoạt động). Cảm ơn.
Warwick

Câu trả lời:


8

Lưu ý rằng bạn đang sử dụng tập lệnh Perl đượcrename phân phối bởi Debian và các công cụ phái sinh (Ubuntu, Mint, cám). Các bản phân phối Linux khác cung cấp một lệnh hoàn toàn khác và ít hữu ích hơn, được gọi là rename.

y/A-Z/a-z/dịch từng ký tự trong phạm vi Athông qua Zthành ký tự tương ứng trong phạm vi athông qua z, tức là các chữ cái viết hoa ASCII thành chữ cái viết thường tương ứng. Để thực hiện dịch ngược lại, sử dụng y/a-z/A-Z/. Một cách khác để viết cùng một lệnh là rename '$_ = uc($_)' *uclà hàm u pper c ase và renamelệnh đổi tên các tệp dựa trên phép chuyển đổi được thực hiện cho $_biến.

rename '…' *chỉ đổi tên các tệp trong thư mục hiện tại, vì đó là những gì *phù hợp. Các tệp chấm (tệp có tên bắt đầu .) cũng bị bỏ qua.

Nếu bạn muốn đổi tên các tệp trong thư mục hiện tại và trong thư mục con theo cách đệ quy, bạn có thể sử dụng findlệnh để duyệt qua thư mục hiện tại theo cách đệ quy. Có một khó khăn ở đây: nếu bạn gọi rename, điều này đổi tên cả thư mục và phần tên cơ sở. Nếu bạn gọi renamevào một thư mục trước khi đệ quy vào nó ( find -exec rename … {} \;), findsẽ bị lẫn lộn vì nó tìm thấy một thư mục nhưng thư mục đó không còn tồn tại vào thời điểm nó cố gắng đi vào nó. Bạn có thể giải quyết vấn đề này bằng cách yêu findcầu duyệt qua một thư mục trước khi hành động, nhưng sau đó bạn cố gắng đổi tên foo/barthành FOO/BARnhưng thư mục FOOkhông tồn tại.

Một cách đơn giản để tránh khó khăn này là làm cho lệnh đổi tên chỉ hành động trên phần tên cơ sở của đường dẫn. Biểu thức chính quy ([^/]*\Z)khớp với phần cuối cùng của đường dẫn không chứa a /.

find . -depth -exec rename 's!([^/]*\Z)!uc($1)!e' {} +

Shell zsh cung cấp nhiều tính năng thuận tiện hơn cho việc đổi tên - thậm chí còn khó hiểu hơn Perl, nhưng phức tạp hơn và thường dễ soạn thảo hơn.

Hàm zmvđổi tên tập tin dựa trên các mẫu. Chạy autoload -U zmvmột lần để kích hoạt nó (đặt dòng này trong của bạn .zshrc).

Trong đối số đầu tiên zmv(mẫu cần thay thế), bạn có thể sử dụng các mẫu ký tự đại diện mạnh mẽ của zsh . Trong đối số thứ hai với zmv(văn bản thay thế), bạn có thể sử dụng các tính năng mở rộng tham số của nó , bao gồm các sửa đổi lịch sử .

zmv -w '**/*' '$1$2:u'

Giải trình:

  • -w - tự động gán các biến số cho từng mẫu ký tự đại diện
  • **/*- tất cả các tệp trong thư mục con, đệ quy ( **/khớp 0, 1 hoặc nhiều cấp thư mục con)
  • $1 - biến số đầu tiên, ở đây khớp với phần thư mục của mỗi đường dẫn
  • $2:u- biến số thứ hai, ở đây khớp với phần tên cơ sở của mỗi đường dẫn, với công cụ :usửa đổi để chuyển đổi giá trị thành chữ hoa

Là một phần thưởng bổ sung, điều này tôn trọng các cài đặt ngôn ngữ xung quanh.

Nếu bạn không chắc chắn về zmvlệnh bạn đã viết, bạn có thể chuyển -ntùy chọn để in những gì lệnh sẽ làm và không thay đổi bất cứ điều gì. Kiểm tra đầu ra và nếu nó làm những gì bạn muốn, hãy chạy lại lệnh mà không -nthực sự hành động.


5

Bị đánh cắp (với một chỉnh sửa nhỏ) từ bài đăng của Gilles tại đây

find <DIR> -depth -type d -exec rename -n 's!/([^/]*/?)$!\U/$1!' {} +


Điều này không hành động đệ quy.
Gilles 'SO- ngừng trở thành ác quỷ'

Thật. Tôi nên đọc câu hỏi đúng. Tôi không có quyền truy cập vào các lệnh đổi tên, nhưng tôi tin rằng điều này sẽ làm việc một cách đệ quy -find <dir> -exec rename 'y/a-z/A-Z/' {} \;
Warwick

Nó phức tạp hơn thế một chút, bởi vì bạn đang đổi tên thư mục trong khi findđang đệ quy vào chúng.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles - OK. Sau khi thực hiện một chút nghiên cứu, có vẻ như tôi cần thêm tùy chọn -depth để tìm tên thư mục được xử lý sau cùng. Vì vậy, find <dir> -depth -exec rename 'y/a-z/A-Z/' {} \;nên xử lý các vấn đề đổi tên thư mục. Chính xác?
Warwick

Không, đó vẫn không làm việc, vì renamenhững thay đổi ví dụ như foo/barđể FOO/BARFOOkhông tồn tại vào thời điểm đó.
Gilles 'SO- ngừng trở nên xấu xa'

2

Tôi muốn hướng dẫn bất cứ ai vẫn liên quan đến câu trả lời này với câu trả lời xuất sắc mà Guiles Quernot đưa ra cho câu hỏi này không yêu cầu find.

Lệnh kết quả sẽ là:

shopt -s globstar
rename -n 'y/a-z/A-Z/' **

Nhưng trước khi chạy, vui lòng đọc câu trả lời được liên kết để biết thêm về các phiên bản bash cũ.

Cuối cùng trong trường hợp ai đó đang tự hỏi y///lệnh này làm gì perl regex. Đây là một liên kết đến các tài liệu liên quan .


1

find -execdir| đổi tên

Đây sẽ là cách tốt nhất để làm điều đó nếu nó không vì sự điên rồ của đường dẫn tương đối, vì nó tránh Perl regex fu chỉ hành động trên tên cơ sở:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find a -depth -execdir rename 's/(.*)/\U$1/' '{}' \;

-execdirđầu tiên cdvào thư mục trước khi chỉ thực hiện trên tên cơ sở.

Thật không may, tôi không thể thoát khỏi PATHphần hack đó , find -execdirtừ chối làm bất cứ điều gì nếu bạn có một đường dẫn tương đối trong PATH...: https://askubfox.com/questions/621132/why-USE-the-execdir-action- is-insecure-for-thư mục-which-is-in-the-path / 1109378 # 1109378


0

Hãy thử điều này sau khi chuyển đến thư mục mà bạn muốn đổi tên các tệp:

for word in `ls -ltr |tail -n +2 |awk '{print $9}'`
do
  a=$(echo $word | tr '[a-z]' '[A-Z]')
  mv $word $a
  echo "Done Successfully"
done

Không phân tích đầu ra của ls (và tại sao bạn ls -lchỉ chạy trên trái đất để cắt bỏ các cột không phải là tên?) Và sử dụng dấu ngoặc kép xung quanh các thay thế khác nhau . Mã của bạn quá phức tạp và phá vỡ tên tệp chứa khoảng trắng và các ký tự đặc biệt khác. Sử dụng findhoặc **/để tái diễn vào các thư mục con, đầu ra của lschỉ dành cho tiêu dùng của con người.
Gilles 'SO- ngừng trở nên xấu xa'
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.