đổi tên hàng loạt (hoặc hiển thị chính xác) các tệp có ký tự đặc biệt


20

Tôi có một loạt các thư mục và thư mục con chứa các tệp có ký tự đặc biệt, như tệp này:

robbie@phil:~$ ls testsktest.txt 
test?sktest.txt

Tìm thấy tiết lộ một chuỗi thoát:

robbie@phil:~$ find testsktest.txt -ls 
424512 4000 -rwxr--r-x   1 robbie   robbie    4091743 Jan 26 00:34 test\323sktest.txt

Lý do duy nhất tôi thậm chí có thể gõ tên của họ trên bàn điều khiển là vì hoàn thành tab. Điều này cũng có nghĩa là tôi có thể đổi tên chúng theo cách thủ công (và loại bỏ ký tự đặc biệt).

Tôi đã đặt LC_ALL thành UTF-8, điều này dường như không có ích (cũng không phải trên vỏ mới):

robbie@phil:~$ echo $LC_ALL
en_US.UTF-8

Tôi đang kết nối với máy bằng ssh từ máy mac. Đây là bản cài đặt Ubuntu:

robbie@phil:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=7.10
DISTRIB_CODENAME=gutsy
DISTRIB_DESCRIPTION="Ubuntu 7.10"

Shell là Bash, TERM được đặt thành màu xterm.

Các tệp này đã tồn tại khá lâu và chúng chưa được tạo bằng cài đặt Ubuntu đó. Vì vậy, tôi không biết các cài đặt mã hóa hệ thống được sử dụng là gì.

Tôi đã thử mọi thứ dọc theo dòng:

find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'

Nhưng tôi không thể tìm thấy một giải pháp làm mọi thứ tôi muốn:

  1. Xác định tất cả các tệp có các ký tự không thể phát (phần trên bỏ qua quá nhiều)
  2. Đối với tất cả các tệp trong cây thư mục (đệ quy), hãy thực hiện mv oldname newname
  3. Tùy chọn, khả năng chuyển ngữ các ký tự đặc biệt như ä thành một (không bắt buộc, nhưng sẽ rất tuyệt)

HOẶC LÀ

  1. Hiển thị chính xác tất cả các tệp này (và không có lỗi trong các ứng dụng khi cố gắng mở chúng)

Tôi có các bit và miếng, như lặp đi lặp lại trên tất cả các tệp và di chuyển chúng, nhưng xác định các tệp và định dạng chúng chính xác cho lệnh mv dường như là phần khó.

Bất kỳ thông tin bổ sung nào về lý do tại sao chúng không hiển thị chính xác hoặc cách "đoán" mã hóa chính xác cũng được hoan nghênh. (Tôi đã thử dùng convmv nhưng dường như nó không thực hiện chính xác những gì tôi muốn: http://j3e.de/linux/convmv/ )


Câu trả lời duy nhất dưới đây theo cách thứ nhất (tìm chúng và đổi tên thành mã hóa mới của bạn), nhưng cách thứ hai cũng sẽ rất thú vị: bây giờ, khi bạn biết mã hóa được sử dụng cho tên tệp từ xa, làm thế nào để ssh đến máy chủ từ xa như vậy một cách mà tên tệp được hiển thị chính xác (và có thể được quản lý bằng cách nhập tên của chúng bằng bàn phím của bạn)?
imz - Ivan Zakharyaschev

Câu trả lời:


21

Tôi đoán bạn thấy ký tự không hợp lệ này vì tên chứa chuỗi byte không hợp lệ UTF-8. Tên tệp trên các hệ thống tệp unix điển hình (bao gồm cả của bạn) là các chuỗi byte và tùy thuộc vào các ứng dụng để quyết định sử dụng mã hóa nào. Ngày nay, có xu hướng sử dụng UTF-8, nhưng nó không phổ biến, đặc biệt là ở các địa phương không bao giờ có thể sống với ASCII đơn giản và đã sử dụng các bảng mã khác kể từ trước khi UTF-8 tồn tại.

Hãy thử LC_CTYPE=en_US.iso88591 lsxem tên tệp có hợp lý trong ISO-8859-1 (latin-1) không. Nếu không, hãy thử các địa phương khác. Lưu ý rằng chỉ có LC_CTYPEcài đặt ngôn ngữ ở đây.

Trong ngôn ngữ UTF-8, lệnh sau sẽ hiển thị cho bạn tất cả các tệp có tên không hợp lệ UTF-8:

grep-invalid-utf8 () {
  perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print'
}
find | grep-invalid-utf8

Bạn có thể kiểm tra xem chúng có ý nghĩa hơn ở một địa điểm khác với recode hoặc iconv :

find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8

Khi bạn đã xác định rằng một loạt các tên tệp nằm trong một mã hóa nhất định (ví dụ: latin1), một cách để đổi tên chúng là

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Điều này sử dụng lệnh đổi tên perl có sẵn trên Debian và Ubuntu. Bạn có thể vượt qua nó -nđể hiển thị những gì nó sẽ làm mà không thực sự đổi tên các tập tin.


Cảm ơn tôi sẽ thử một số trong những điều này sau ngày hôm nay! Có vẻ như đây sẽ là câu trả lời được chấp nhận :)
RobbieV

Việc tìm kiếm | Lệnh grep '[[: print:]]' dường như chỉ trả về tất cả các tệp. Không nên UTF-8 tương thích với nhiều bảng mã khác với các ký tự "bình thường"?
RobbieV

@RobbieV: Tôi đánh máy và có nghĩa là grep [^[:print:]]tìm kiếm các ký tự không thể in được. Nhưng tôi vừa thử nghiệm với GNU grep và các chuỗi UTF-8 không hợp lệ không bị bắt bởi [^[:print:]](điều này có nghĩa là chúng không phải là ký tự không thể in được, chúng hoàn toàn không phải là ký tự). Tôi đã chỉnh sửa bài đăng của mình với cách xếp hàng dài hơn với các chuỗi utf8 không hợp lệ. Lưu ý rằng tôi cũng đã sửa hướng recodeiconvví dụ.
Gilles 'SO- ngừng trở nên xấu xa'

Điều đó đã làm việc hoàn hảo. Đã thử tất cả các lệnh ngoại trừ lệnh iconv, và tất cả chúng đều hoạt động như mong đợi. Ma thuật thuần túy!
RobbieV

Ngay cả mã hóa latin1 được đề xuất là chính xác :)
RobbieV

1

Tôi biết đây là một câu hỏi cũ nhưng tôi đã tìm kiếm cả đêm cho một giải pháp tương tự. Tôi đã tìm thấy một vài lời khuyên hữu ích nhưng chúng không thực hiện chính xác những gì tôi cần, vì vậy tôi phải trộn và kết hợp một vài để có được kết quả chính xác mà tôi đang tìm kiếm

chỉ cần xóa các ký tự đặc biệt và thay thế chúng bằng dấu chấm (.)

for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done

để sử dụng trong một cronjob tôi đã làm như sau để chạy mỗi phút

*/1 * * * * cd /path/to/files/ && for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done >/dev/null 2>&1

Tôi hy vọng ai đó thấy điều này hữu ích vì nó đã làm cho ngày của tôi :)


(1) Để rõ ràng, bạn có thể muốn thay đổi `…`thành$(…) - xem cái này , cái nàycái này . (2) Bạn phải luôn trích dẫn các tham chiếu biến shell của mình (ví dụ "$f":) trừ khi bạn có lý do chính đáng để không và bạn chắc chắn rằng bạn biết bạn đang làm gì. Điều này áp dụng ngay cả với echo "$f" | sed …. Nó cũng áp dụng cho toàn bộ biểu thức $(…)(hoặc `…`); ví dụ mv "$f" "$(echo "$f" | sed "…")". Tiết (Cont'd)
Scott

(Tiếp theo) Nhiều (3) Bạn nên nói , để bảo vệ chống lại tên tập tin bắt đầu bằng . (4) Nếu bạn có các tệp có tên là Drake foo ♥ bar.txt các tập tin sẽ bị phá hủy. (5) Tại sao bạn muốn làm điều này một lần mỗi phút? mv -- "$f" …-
Scott

Tôi có một tập lệnh torrent tự động tải tập tin. và đôi khi một số tệp có các ký tự trong đó sẽ loại bỏ trình tải lên. do đó, chỉ cần đổi tên các tệp có ký tự đặc biệt, cron của tôi đã khắc phục tất cả các sự cố của tôi và trình tải lên thực hiện công việc của nó một cách trơn tru.
Topps70

vì vậy (cái này tha, t là - down_loaded.ext) biến thành (this.fi.le.tha.t.was.down.loaded.ext)
Topps70

0

Bây giờ, khi bạn biết mã hóa nào được sử dụng cho tên tệp ở đầu từ xa ("latin1" - theo các nhận xét cho câu trả lời đầu tiên), bạn cũng có thể làm theo cách thứ hai - chạy một thuật ngữ địa phương và ssh theo cách đó cách mà tên tệp từ xa được hiển thị chính xác (thay vì cách thứ nhất: đổi tên chúng) .

Giống như tôi , bạn có thể bắt đầu một thiết bị đầu cuối cục bộ sẽ hoạt động trong mã hóa đặc biệt đó, có lẽ, như thế này:

LC_ALL = en_US.latin1 xvt &

xvt là viết tắt của chương trình thiết bị đầu cuối của bạn.

Có lẽ, miền địa phương hiện tại được gọi en_US.iso88591, và không en_US.latin1, như tôi giả định.


0

Điều này không đáp ứng các yêu cầu số lượng lớn, nhưng tôi vừa gặp một vấn đề tương tự khi tôi có nhiều phiên bản của một tệp có tên tương tự chỉ khác nhau bởi một ký tự lạ. Thật không may, điều này có nghĩa là tôi không thể đổi tên những người phạm tội bằng cách sử dụng thủ thuật ký tự đại diện mà tôi thường sử dụng.

Cuối cùng, tôi đã sử dụng Filezilla để kết nối với tư cách là máy khách SFTP, duyệt qua các tệp và đổi tên chúng bằng GUI. Filezilla xử lý các ký tự tinh ranh khá tốt.

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.