Xử lý tên tệp có ký tự đầu tiên đặc biệt (ví dụ:)


30

Gần đây tôi đã bắt gặp một tập tin có tên bắt đầu bằng ký tự '♫'. Tôi muốn sao chép tập tin này, đưa nó vào ffmpegvà tham chiếu nó theo nhiều cách khác nhau trong thiết bị đầu cuối. Tôi thường tự động hoàn thành tên tập tin kỳ lạ nhưng điều này thất bại vì tôi thậm chí không thể gõ chữ cái đầu tiên.

Tôi không muốn chuyển sang chuột để thực hiện thao tác sao chép-dán. Tôi không muốn ghi nhớ một loạt các mã cho các tình huống có thể xảy ra. Giải pháp đặc biệt của tôi là chuyển sang vim, dán !lsvà sao chép ký tự trong câu hỏi, sau đó thoát và dán nó vào thiết bị đầu cuối. Điều này làm việc nhưng khá kinh khủng.

Có cách nào dễ dàng hơn để đối phó với các kịch bản như vậy?

LƯU Ý: Tôi đang sử dụng vỏ cá nếu nó thay đổi mọi thứ.


7
Bạn có thể sử dụng các phần khác của tệp để tạo một biểu thức chính quy để làm việc với nó không? *restoffile.avihoặc thứ gì đó giống thế này?
slm

1
Trong trường hợp này, tên còn lại là hỗn hợp của Kanji và Katakana (chữ viết tiếng Nhật), vì vậy không dễ dàng.
Mã PIN

3
Hiểu rồi, cứ nghĩ tôi hỏi. Câu trả lời của jimmij có giải quyết được không? Ngoài ra, bạn có phiền dán ảnh chụp màn hình của các tập tin vi phạm? Nó có thể sẽ hữu ích cho những người khác có thể đọc điều này sau này.
slm

1
Tôi đang cố gắng để làm cho nó hoạt động ngay bây giờ. Tôi không biết làm thế nào để đăng một màn hình nhưng chạy các lệnh sau sẽ cung cấp cho bạn vấn đề giả của tôi:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode

1
Với zsh, bạn có thể sử dụng các tùy chọn để có tab cung cấp cho bạn một menu từ đó bạn có thể chọn tệp thích hợp.
Kevin

Câu trả lời:


35

Nếu ký tự đầu tiên của tên tệp có thể in được nhưng cả chữ và số đều có thể sử dụng [[:punct:]]toán tử toàn cầu:

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt

Hmm Tôi không biết về các nhà khai thác toàn cầu này, tôi đã đọc chúng và tìm hiểu một chút (cảm ơn bạn), nó giải quyết vấn đề tôi gặp phải đó là một tập tin kỳ lạ trong thư mục của tôi. Bây giờ tôi gặp vấn đề này với vô số Tôi nên hỏi một câu hỏi mới hoặc cập nhật câu hỏi này?
Mã PIN

Tôi đã chấp nhận câu trả lời của bạn, tôi sẽ đăng kịch bản thứ hai vào ngày mai khi tôi có thời gian. Cảm ơn bạn vì sự giúp đỡ.
Mã PIN

6

Điều đơn giản nhất xảy ra với tôi là ls [^a-zA-Z0-9]*và nó thực hiện mánh khóe cho tôi, nhưng câu trả lời của terdon là tốt hơn trong việc gây chú ý đến tùy chọn shell extglob hoặc thậm chí là một cách tiếp cận độc lập với vỏ.


Đây là một cú đâm đủ tốt vào nó. Bạn có thể ls [^[:alnum:]]*cho điều tương tự. Nhưng nó tốt hơn để sử dụng lớp nhân vật đó , chứ không phải là lớp (es) nó không phải là ; do đó ls [[:punct:]]*sẽ liệt kê tập tin này.
Giàu

6

ls có một số công tắc (như --quote-name, --escape, --literal) để xử lý các ký tự không thể in được, nhưng trong trường hợp này có vẻ như ký tự là "có thể in" nhưng không "đánh máy được" (ít nhất là trên bàn phím của tôi! ), vì vậy không có công tắc nào trong số này có vẻ hữu ích.

Do đó, như một cách tiếp cận "vũ phu" chung để loại bỏ các tệp có bất kỳ ký tự nào trong tên của chúng, bạn có thể thực hiện việc này:

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ♫
     2  f1.txt
     3  f2.txt

Tìm dòng chứa tệp vi phạm. Rất có thể nó sẽ là dòng thứ 1, nhưng hãy nói nó là dòng thứ 5. In dòng 5 và hex mã hóa nó:

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....

Bỏ qua ký tự 0a (dòng mới), xây dựng chuỗi thoát và sử dụng tùy chọn -e của echo để dịch các lối thoát:

$ echo -e '\xe2\x99\xab'
♫

Bây giờ bạn có thể sao chép / di chuyển / xóa nó như thế này:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘♫’ -> ‘better_name’

Ngoài ra, nếu bạn không bị giới hạn sử dụng shell script, bạn có thể thực hiện nó trong Python như thế này:

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
♫
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')

Sử dụng phương pháp này, bạn có thể xử lý nhiều tệp, bạn chỉ cần viết logic để chọn đúng tệp và đổi tên chúng mà không bị ghi đè, v.v .:

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'

5

Một cách tiếp cận tương tự sẽ là liệt kê tất cả các tệp không bắt đầu bằng các ký tự "bình thường". Trong bash bạn có thể làm điều này với

$ shopt -s extglob
$ ls !([[:alpha:]]*)

Tuy nhiên, điều đó dường như không có sẵn fish, vì vậy bạn có thể sử dụng findthay thế:

$ find . -type f -not -name '[[:alpha:]]*'

4

Đổi tên liên kết

Một cách tiếp cận để xử lý tên tệp có các ký tự đặc biệt - như các ký tự đầu tiên hoặc các nơi khác trong tên tệp là đổi tên thành các tên đơn giản hơn .

Điều này có thể được sử dụng ngay cả khi bạn cần giữ tên tệp gốc : Đổi tên một bản sao của tên tệp.
Điều đó có thể được thực hiện bằng cách sao chép các tập tin, nhưng cũng bằng cách tạo liên kết tượng trưng hoặc liên kết cứng vào các tệp và đổi tên chúng. cptạo liên kết tượng trưng thay vì bản sao với tùy chọn -s( -lđối với liên kết cứng).

Sử dụng "cai nghiện" để xóa tên

Để đổi tên thành tên tệp sạch, detoxcó thể được sử dụng; Nó đổi tên tập tin để dọn sạch tên tập tin theo các quy tắc khác nhau như được định nghĩa trong một detoxrctập tin. Theo mặc định, các ký tự UTF8 chỉ bị xóa; Với tùy chọn, -s utf_8-onlychúng được thay thế bằng _:

$ touch '♫ 漢字カ' ♫foo
$ ls -1
♫foo
♫ 漢字カ
$ detox -s utf_8-only * 
$ ls -1                
_ ___
_foo


"cai nghiện" trên các liên kết tượng trưng

Kết hợp với làm việc trên các liên kết tượng trưng như được mô tả ở trên:

$ mkdir orig
$ cd orig 
$ touch '♫ 漢字カ' ♫foo
$ cd ..
$ mkdir clean
$ cd clean 
$ cp -s ../orig/* .
$ ll               
lrwxrwxrwx 1 14 Oct  8 05:52 ♫foo -> ../orig/♫foo
lrwxrwxrwx 1 21 Oct  8 05:52 ♫\ 漢字カ -> ../orig/♫\ 漢字カ
$ ls -1
♫foo
♫ 漢字カ
$ detox --special -s utf_8-only *
$ ll                                
lrwxrwxrwx 1 21 Oct  8 05:52 _\ ___ -> ../orig/♫\ 漢字カ
lrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/♫foo

2

Tôi không sử dụng fish, nhưng tài liệu nói rằng bạn có thể nhập một ký tự Unicode bằng cách thêm tiền tố mã ký tự hex của nó bằng \u(cho các ký tự 16 bit) hoặc \U(cho các ký tự 32 bit). Tôi nghĩ rằng mã cho 491eb, vì vậy bạn có thể làm:

mv \U000491ebabc.mp3 abc.mp3

để đổi tên ♫abc.mp3.

Lưu ý rằng bạn cần các số 0 đứng đầu, nếu không abcở cuối sẽ được coi là các chữ số hex và một phần của mã ký tự; đối với ký tự 32 bit, bạn cần nhập 8 chữ số.


2

Tôi không biết có phải đã xảy ra vào năm 2014 khi bạn đặt câu hỏi không, nhưng trong các phiên bản hiện tại của fish(kể từ năm 2019), bạn có thể nhấn Tabhai lần, để có được lựa chọn kiểu zsh nơi bạn có thể sử dụng các phím mũi tên để Trực quan chọn tệp bạn muốn mà không phải nhập bất kỳ phần nào của tên tệp.


2

không hỗ trợ ký tự đại diện khung theo thiết kế.

function find_special_filename
    find ! -path './.*' -name '[^-.a-zA-Z0-9_]*' $argv
end

Lệnh không tìm kiếm trong danh bạ ẩn và hiển thị tên tập tin mà không bắt đầu bằng các ký tự letters, digits, . _ -(cf tài liệu của find).

Lưu ý: $argv là một biến mảng đặc biệt (Fish shell) có chứa các đối số hàm do đó lệnh bên dưới có thể nhận bất kỳ biểu thức nào (ví dụ bí danh ).

find_special_filename -exec mv '{}' misc/ \;

¹ Trong thực tế, cá hỗ trợ mở rộng khung (biến mảng mở rộng) nhưng Bash sử dụng một thuật ngữ (tham số và tên tập tin mở rộng).


1

Sử dụng zshvà gõ những gì tiếp theo. ZSH hỗ trợ tự động hoàn thành mờ và có thể đối phó với nó. (Nó đặc biệt tốt với plugin OH-MY-ZSH .)


0

Bạn đã không nói liệu bạn có muốn giữ những tên tập tin có vấn đề này hay không. Một giải pháp có thể là khắc phục sự cố một lần và mãi mãi bằng cách đổi tên (một số hoặc tất cả) các tệp của bạn thành tên mà bạn có thể nhập bằng cách chạy tập lệnh này:

#!/bin/sh
for old in *
do
      printf "%s ...? " "$old"
      if read new  &&  [ "$new" != "" ]
      then
             mv -i "$old" "$new"
      fi
done

Điều này sẽ liệt kê tên tệp hiện có của bạn, mỗi tên theo sau ...?. Chỉ cần gõ Enterđể để lại một tập tin như là; hoặc nhập tên mới để đổi tên nó. Các-i tùy chọn sẽ gây ra nó để yêu cầu bạn xác nhận ghi đè nếu bạn chỉ định tên của một tập tin hiện có.

Kịch bản này có thể được sửa đổi theo nhiều cách:

  • Bạn có thể sửa đổi ký tự đại diện ( *) thành thứ gì đó hạn chế hơn, ví dụ:*.avi *.mov , vì vậy bạn không phải xem mọi tệp.
  • Bạn có thể thay đổi mvđểcp , vì vậy bạn giữ một bản sao của tệp với tên hiện tại của nó và tạo một bản sao (tạm thời?) Với một tên có thể đánh máy.
  • Bạn có thể tạo một tên tệp mới dựa trên tên tệp hiện có. Ví dụ,

    if read pfx  &&  [ "$pfx" != "" ]
    then
            mv -i "$old" "$pfx$old"
    fi
    

    cho phép bạn đặt một tiền tố trước tên cũ. Nếu bạn chọn một tiền tố duy nhất, điều này sẽ cho phép bạn sử dụng tự động hoàn thành.

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.