การจัดการกับชื่อไฟล์ด้วยอักขระตัวแรกพิเศษ (เช่น♫)


30

ฉันเพิ่งเจอไฟล์ที่ชื่อขึ้นต้นด้วยตัวอักษร '♫' ฉันต้องการคัดลอกไฟล์นี้ให้อาหารมันffmpegและอ้างอิงในรูปแบบอื่น ๆ ใน terminal ฉันมักจะเติมชื่อไฟล์แปลก ๆ ให้โดยอัตโนมัติ แต่สิ่งนี้ล้มเหลวเนื่องจากฉันไม่สามารถพิมพ์อักษรตัวแรกได้

ฉันไม่ต้องการเปลี่ยนไปใช้เมาส์เพื่อดำเนินการทำสำเนาวาง ฉันไม่ต้องการจดจำรหัสจำนวนมากสำหรับสถานการณ์ที่เป็นไปได้ โซลูชันเฉพาะกิจของฉันคือการสลับvimวาง!lsและคัดลอกอักขระที่เป็นปัญหาจากนั้นออกและวางลงในเทอร์มินัล มันใช้งานได้ แต่ก็ค่อนข้างน่ากลัว

มีวิธีที่ง่ายกว่าในการจัดการกับสถานการณ์ดังกล่าวหรือไม่?

หมายเหตุ:ฉันกำลังใช้ตู้ปลาถ้ามันเปลี่ยนสิ่งต่าง ๆ


7
คุณสามารถใช้ส่วนอื่น ๆ ของไฟล์เพื่อสร้าง regex เพื่อทำงานกับมันได้หรือไม่? *restoffile.aviหรืออะไรแบบนี้
slm

1
ในกรณีนี้ชื่อที่เหลือคือส่วนผสมของคันจิและคาตาคานะ (สคริปต์ภาษาญี่ปุ่น) ดังนั้นจึงไม่สะดวก
ZirconCode

3
เข้าใจแค่คิดว่าฉันจะถาม คำตอบของ jimmij แก้ได้ไหม? คุณต้องการวางภาพหน้าจอของไฟล์ที่ละเมิดหรือไม่ อาจเป็นประโยชน์กับคนอื่น ๆ ที่อาจจะอ่านในภายหลัง
slm

1
ฉันพยายามทำให้มันทำงานได้แล้ว ฉันไม่ทราบวิธีโพสต์ screeny แต่การรันคำสั่งต่อไปนี้จะทำให้คุณมีปัญหาการเยาะเย้ยของฉัน:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode

1
ด้วย zsh คุณสามารถใช้ตัวเลือกเพื่อให้แท็บให้เมนูซึ่งคุณสามารถเลือกไฟล์ที่เหมาะสม
เควิน

คำตอบ:


35

หากอักขระตัวแรกของชื่อไฟล์สามารถพิมพ์ได้ แต่ไม่ใช่ตัวอักษรและตัวเลขและช่องว่างคุณสามารถใช้[[:punct:]]โอเปอเรเตอร์ glob:

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

อืมฉันไม่ทราบเกี่ยวกับโอเปอเรเตอร์ glob เหล่านี้ฉันอ่านพวกเขาและเรียนรู้เล็กน้อย (ขอบคุณ) มันแก้ปัญหาที่ฉันมีซึ่งเป็นไฟล์แปลกเดียวใน dir ของฉันตอนนี้ฉันมีปัญหากับมากมาย ไฟล์ฉันควรถามคำถามใหม่หรืออัปเดตคำถามนี้หรือไม่
ZirconCode

ฉันยอมรับคำตอบของคุณแล้วฉันจะโพสต์สถานการณ์ที่สองในวันพรุ่งนี้เมื่อฉันมีเวลา ขอขอบคุณสำหรับความช่วยเหลือ.
ZirconCode

6

สิ่งที่ง่ายที่สุดที่เกิดขึ้นกับฉันก็คือls [^a-zA-Z0-9]*และมันก็ใช้กลอุบายสำหรับฉัน แต่คำตอบของ terdon นั้นดีกว่าในการนำความสนใจไปที่ตัวเลือกเชลล์ extglob หรือแม้แต่วิธีที่เป็นอิสระจากเชลล์


นี่เป็นการแทงที่ดีพอสมควร คุณสามารถls [^[:alnum:]]*ทำสิ่งเดียวกัน แต่มันเป็นเรื่องดีที่จะใช้ตัวละครคลาสมันเป็นมากกว่าชั้น (e) มันไม่ได้ ; ดังนั้นls [[:punct:]]*จะแสดงรายการไฟล์นี้
รวย

6

ls มีสวิตช์บางตัว (เช่น --quote-name, --escape, - literal) สำหรับจัดการกับอักขระที่ไม่สามารถพิมพ์ได้ แต่ในกรณีนี้ดูเหมือนว่าตัวละครนั้นเป็น "พิมพ์ได้" แต่ไม่ใช่ "พิมพ์ได้" (อย่างน้อยบนแป้นพิมพ์ของฉัน! ) ดังนั้นจึงไม่มีสวิตช์เหล่านี้ดูเหมือนจะช่วยได้

ดังนั้นตามวิธีการทั่วไป "กำลังดุร้าย" ในการกำจัดไฟล์ที่มีตัวอักษรใด ๆ ในชื่อคุณสามารถทำได้ดังนี้:

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

ค้นหาบรรทัดที่มีไฟล์ที่ละเมิด ค่อนข้างเป็นไปได้ว่ามันจะเป็นบรรทัดที่ 1 แต่สมมุติว่าเป็นบรรทัดที่ 5 พิมพ์บรรทัดที่ 5 และเข้ารหัส hex:

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

ละเว้นอักขระ 0a (ขึ้นบรรทัดใหม่) สร้างสตริง escape และใช้อ็อพชัน -e ของ echo เพื่อแปล escapes:

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

ตอนนี้คุณสามารถคัดลอก / ย้าย / ลบแบบนี้:

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

นอกจากนี้หากคุณไม่ได้ จำกัด การใช้เชลล์สคริปต์คุณสามารถทำได้ใน Python ดังนี้:

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

ใช้วิธีการนี้คุณสามารถประมวลผลไฟล์จำนวนมากคุณเพียงแค่ต้องเขียนตรรกะสำหรับการเลือกไฟล์ที่ถูกต้องและเปลี่ยนชื่อพวกเขาโดยไม่ต้องอุดตัน ฯลฯ :

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

แนวทางที่คล้ายกันคือการแสดงรายการไฟล์ทั้งหมดที่ไม่ได้ขึ้นต้นด้วยตัวอักษร "ปกติ" ในทุบตีคุณสามารถทำได้ด้วย

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

อย่างไรก็ตามดูเหมือนว่าจะไม่สามารถใช้ได้fishดังนั้นคุณสามารถใช้findแทน:

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

4

เปลี่ยนชื่อ symlink

วิธีการหนึ่งที่จะจับชื่อไฟล์ที่มีตัวอักษรพิเศษ - เป็นตัวละครเป็นครั้งแรกหรือที่อื่น ๆ ในชื่อไฟล์คือการเปลี่ยนชื่อชื่อที่เรียบง่าย

สามารถใช้งานได้แม้ว่าคุณจะต้องเก็บชื่อไฟล์ดั้งเดิมไว้ : เปลี่ยนชื่อสำเนาของชื่อไฟล์
ที่สามารถทำได้โดยการคัดลอกไฟล์ แต่ยังโดยการสร้างsymlink หรือฮาร์ดลิงก์ไปยังไฟล์และเปลี่ยนชื่อเหล่านี้ cpสร้าง symlink แทนการทำสำเนาด้วยตัวเลือก-s( -lสำหรับ hardlinks)

ใช้ "ดีท็อกซ์" เพื่อล้างชื่อ

สำหรับการเปลี่ยนชื่อเป็นล้างชื่อไฟล์detoxสามารถใช้ได้ มันเปลี่ยนชื่อไฟล์เพื่อล้างชื่อไฟล์ตามกฎต่าง ๆ ที่กำหนดไว้ในdetoxrcไฟล์ โดยค่าเริ่มต้นอักขระ UTF8 จะถูกลบออก ด้วยตัวเลือก-s utf_8-onlyพวกเขาจะถูกแทนที่ด้วย_:

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


"ดีท็อกซ์" บน symlinks

รวมกับการทำงานกับ symlink ดังอธิบายข้างต้น:

$ 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

ฉันไม่ได้ใช้fishแต่เอกสารบอกว่าคุณสามารถป้อนอักขระ Unicode ได้โดยใส่รหัสอักขระฐานสิบหกด้วย\u(สำหรับอักขระ 16 บิต) หรือ\U(สำหรับอักขระ 32 บิต) ฉันคิดว่ารหัสสำหรับเป็น491ebดังนั้นคุณสามารถทำได้:

mv \U000491ebabc.mp3 abc.mp3

♫abc.mp3ที่จะเปลี่ยนชื่อ

โปรดทราบว่าคุณต้องการเลขศูนย์นำหน้าไม่เช่นabcนั้นในตอนท้ายจะถือว่าเป็นเลขฐานสิบหกและเป็นส่วนหนึ่งของรหัสอักขระ สำหรับอักขระ 32 บิตคุณต้องป้อนตัวเลข 8 หลัก


2

ฉันไม่ทราบว่าเป็นกรณีนี้หรือไม่ในปี 2014 เมื่อคุณถามคำถาม แต่ในรุ่นปัจจุบันของfish(ณ ปี 2019) คุณสามารถกดTabสองครั้งเพื่อรับการเลือกสไตล์ zsh ซึ่งคุณสามารถใช้ปุ่มลูกศรเพื่อ มองเห็นไฟล์ที่คุณต้องการโดยไม่ต้องพิมพ์ส่วนใด ๆ ของชื่อไฟล์


2

ปลาไม่รองรับสัญลักษณ์ตัวแทน bracketโดยการออกแบบ

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

คำสั่งที่ไม่ได้ค้นหาในไดเรกทอรีและแสดงซ่อนชื่อไฟล์ที่ไม่ได้เริ่มต้นด้วยตัวอักษรletters, digits, . _ -(CF เอกสารของfind)

หมายเหตุ: $argvเป็นตัวแปรอาเรย์พิเศษ (Fish shell) ที่มีอาร์กิวเมนต์ของฟังก์ชันดังนั้นคำสั่งพื้นฐานอาจได้รับการแสดงออกใด ๆ (เช่นนามแฝง )

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

¹ อันที่จริงแล้ว Fish สนับสนุนการขยายตัวของวงเล็บ (การขยายตัวแปรอาร์เรย์) แต่ Bash ใช้คำศัพท์อื่น (การขยายพารามิเตอร์และการขยายชื่อไฟล์)



0

คุณไม่ได้พูดว่าต้องการเก็บชื่อไฟล์ที่มีปัญหาเหล่านี้หรือไม่ วิธีแก้ปัญหาหนึ่งอาจจะ "แก้ไข" ปัญหาครั้งเดียวและทั้งหมดโดยการเปลี่ยนชื่อ (บางส่วนหรือทั้งหมด) ไฟล์ของคุณเป็นชื่อที่คุณสามารถพิมพ์โดยใช้สคริปต์นี้:

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

...?นี้จะแสดงรายการชื่อไฟล์ที่มีอยู่ของแต่ละคนตามมาด้วย เพียงพิมพ์Enterเพื่อปล่อยไฟล์ตามที่เป็นอยู่; หรือพิมพ์ชื่อใหม่เพื่อเปลี่ยนชื่อ -iตัวเลือกที่จะทำให้มันขอให้คุณยืนยันการเขียนทับถ้าคุณระบุชื่อของไฟล์ที่มีอยู่อีก

สคริปต์นี้สามารถแก้ไขได้หลายวิธี:

  • คุณสามารถปรับเปลี่ยนไวด์การ์ด ( *) เป็นสิ่งที่ จำกัด มากขึ้นเช่น*.avi *.movดังนั้นคุณไม่จำเป็นต้องดูไฟล์ทุกไฟล์
  • คุณสามารถเปลี่ยนเป็นmvเพื่อcpให้คุณเก็บสำเนาของไฟล์ด้วยชื่อปัจจุบันและสร้างสำเนา (ชั่วคราว?) ด้วยชื่อที่พิมพ์ได้
  • คุณสามารถสร้างชื่อไฟล์ใหม่ตามชื่อไฟล์ที่มีอยู่ ตัวอย่างเช่น,

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

    ซึ่งช่วยให้คุณตบหน้าคำนำหน้าชื่อเก่าได้ หากคุณเลือกคำนำหน้าที่ไม่ซ้ำกันสิ่งนี้จะช่วยให้คุณใช้การเติมข้อความอัตโนมัติ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.