เปลี่ยนชื่อไฟล์จำนวนมาก (หรือแสดงอย่างถูกต้อง) ด้วยอักขระพิเศษ


20

ฉันมีกลุ่มไดเรกทอรีและไดเรกทอรีย่อยที่มีไฟล์ที่มีอักขระพิเศษเช่นไฟล์นี้:

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

ค้นหาพบลำดับการหลบหนี:

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

เหตุผลเดียวที่ฉันสามารถพิมพ์ชื่อของพวกเขาบนคอนโซลได้ก็เพราะความสมบูรณ์ของแท็บ นอกจากนี้ยังหมายความว่าฉันสามารถเปลี่ยนชื่อพวกเขาด้วยตนเอง (และตัดอักขระพิเศษ)

ฉันได้ตั้งค่า LC_ALL เป็น UTF-8 ซึ่งดูเหมือนจะไม่ช่วย (ยังไม่ได้อยู่ในเปลือกใหม่):

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

ฉันกำลังเชื่อมต่อกับเครื่องโดยใช้ ssh จาก mac ของฉัน มันคือการติดตั้ง Ubuntu:

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

Shell คือ Bash TERM ตั้งค่าเป็น xterm-color

ไฟล์เหล่านี้อยู่ที่นั่นมาระยะหนึ่งแล้วและยังไม่ได้สร้างขึ้นโดยใช้การติดตั้งของ Ubuntu ดังนั้นฉันไม่รู้ว่าการตั้งค่าการเข้ารหัสระบบเคยเป็นอย่างไร

ฉันได้ลองทำสิ่งต่าง ๆ ตาม:

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

แต่ฉันไม่พบวิธีแก้ปัญหาที่ทำทุกอย่างที่ฉันต้องการ:

  1. ระบุไฟล์ทั้งหมดที่มีตัวละครที่ไม่สามารถเล่นได้ (ด้านบนจะข้ามไปมากจนเกินไป)
  2. สำหรับไฟล์ทั้งหมดในแผนผังไดเร็กทอรี (เรียกซ้ำ) ให้เรียกใช้ mv oldname newname
  3. เป็นทางเลือกความสามารถในการแปลอักขระพิเศษเช่นäถึง a (ไม่จำเป็น แต่น่ากลัวมาก)

หรือ

  1. แสดงไฟล์เหล่านี้อย่างถูกต้อง (และไม่มีข้อผิดพลาดในแอปพลิเคชันเมื่อพยายามเปิดไฟล์)

ฉันมีบิตและชิ้นส่วนเหมือนวนซ้ำทุกไฟล์และย้ายไปมา แต่การระบุไฟล์และการจัดรูปแบบไฟล์เหล่านั้นอย่างถูกต้องสำหรับคำสั่ง mv นั้นดูเหมือนจะเป็นส่วนที่ยาก

ข้อมูลเพิ่มเติมใด ๆ เกี่ยวกับสาเหตุที่แสดงไม่ถูกต้องหรือวิธี "คาดเดา" การเข้ารหัสที่ถูกต้องก็ยินดีต้อนรับเช่นกัน (ฉันได้ลองใช้ convmv แต่ดูเหมือนว่าจะไม่ทำสิ่งที่ฉันต้องการ: http://j3e.de/linux/convmv/ )


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

คำตอบ:


21

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

ลองLC_CTYPE=en_US.iso88591 lsดูว่าชื่อไฟล์เหมาะสมใน ISO-8859-1 (latin-1) หรือไม่ หากไม่เป็นเช่นนั้นให้ลองสถานที่อื่น โปรดทราบว่าเฉพาะการLC_CTYPEตั้งค่าสถานที่มีความสำคัญที่นี่

ในโลแคล UTF-8 คำสั่งต่อไปนี้จะแสดงไฟล์ทั้งหมดที่มีชื่อไม่ถูกต้อง 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

คุณสามารถตรวจสอบว่าพวกเขามีเหตุผลในภาษาอื่นด้วยrecodeหรือiconv :

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

เมื่อคุณทราบแล้วว่าชื่อไฟล์หลาย ๆ ไฟล์มีการเข้ารหัส (เช่น latin1) วิธีหนึ่งในการเปลี่ยนชื่อไฟล์คือ

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

ใช้คำสั่งเปลี่ยนชื่อ perl ที่มีอยู่ใน Debian และ Ubuntu คุณสามารถส่งมัน-nเพื่อแสดงสิ่งที่มันจะทำโดยไม่ต้องเปลี่ยนชื่อไฟล์จริง


ขอบคุณฉันจะลองสิ่งเหล่านี้ในวันนี้! ดูเหมือนว่านี่จะเป็นคำตอบที่ได้รับการยอมรับ :)
RobbieV

การค้นหา | grep '[[: print:]]' ดูเหมือนว่าจะส่งคืนไฟล์ทั้งหมด ไม่ควร UTF-8 เข้ากันได้กับการเข้ารหัสอื่น ๆ ที่มีอักขระ "ปกติ" หรือไม่?
RobbieV

@ RobbieV: ฉันพิมพ์ผิดและตั้งใจgrep [^[:print:]]จะค้นหาตัวอักษรที่ไม่สามารถพิมพ์ได้ แต่ฉันเพิ่งทดสอบกับ GNU grep และลำดับ UTF-8 ที่ไม่ถูกต้องนั้นไม่ได้ถูกจับ[^[:print:]](ซึ่งดูสมเหตุสมผลเพราะมันไม่ใช่อักขระที่ไม่สามารถพิมพ์ได้ ฉันแก้ไขโพสต์ของฉันด้วยวิธีการ grepping บรรทัดที่ยาวขึ้นด้วยลำดับ utf8 ที่ไม่ถูกต้อง โปรดทราบว่าฉันได้กำหนดทิศทางrecodeและiconvตัวอย่าง
Gilles 'หยุดชั่วร้าย'

มันทำงานได้อย่างสมบูรณ์ ลองคำสั่งทั้งหมดยกเว้นไอคอน iconv และทำงานได้ตามที่คาดไว้ เวทมนตร์บริสุทธิ์!
RobbieV

แม้ปัญหาการเข้ารหัส latin1 เป็นหนึ่งที่ถูกต้อง :)
RobbieV

1

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

เพื่อลบอักขระพิเศษและแทนที่ด้วยจุด (.)

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

เพื่อใช้ใน cronjob ฉันทำต่อไปนี้เพื่อให้ทำงานทุกนาที

*/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

ฉันหวังว่าจะมีคนพบว่าสิ่งนี้มีประโยชน์เพราะทำให้วันของฉัน :)


(1) เพื่อความชัดเจนคุณอาจต้องการที่จะเปลี่ยน`…`ไป$(…)- เห็นนี้ , นี้และนี้ (2) คุณควรอ้างอิงการอ้างอิงตัวแปรเชลล์ของคุณ (เช่น"$f") เว้นแต่คุณจะมีเหตุผลที่ดีที่จะไม่ทำและคุณแน่ใจว่าคุณรู้ว่าคุณกำลังทำอะไร echo "$f" | sed …นี้ใช้แม้จะ นอกจากนี้ยังใช้กับนิพจน์ทั้งหมด$(…)(หรือ`…`) เช่นmv "$f" "$(echo "$f" | sed "…")". … (ต่อ)
สกอตต์

(ต่อ) ... (3) คุณควรจะพูดว่าเพื่อป้องกันชื่อไฟล์ที่เริ่มต้นด้วย (4) หากคุณมีไฟล์ชื่อ“ foo ♥ bar.txt” และ“ foo ♠ bar.txt” สิ่งนี้จะพยายามเปลี่ยนชื่อไฟล์ทั้งสองเป็น“ foo.bar.txt” ซึ่งอาจเป็นสาเหตุหนึ่งของ ไฟล์ที่จะถูกทำลาย (5) ทำไมบนโลกนี้คุณต้องการทำสิ่งนี้ทุก ๆ นาที? mv -- "$f" …-
สกอตต์

ฉันมีสคริปต์ฝนตกหนักที่ดาวน์โหลดไฟล์อัตโนมัติ และบางครั้งไฟล์บางไฟล์อาจมีตัวละครอยู่ในตัวซึ่งทำให้ผู้อัปโหลดไม่ทำงาน ดังนั้นโดยการเปลี่ยนชื่อไฟล์ด้วยตัวอักษรพิเศษ cron ของฉันแก้ไขปัญหาทั้งหมดของฉันและผู้อัปโหลดทำงานได้อย่างราบรื่น
Topps70

ดังนั้น (สิ่งนี้คือ tha, t คือ - down_loaded.ext) กลายเป็น (this.fi.le.tha.t.was.down.loaded.ext)
Topps70

0

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

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

LC_ALL = en_US.latin1 xvt &

xvt ย่อมาจากโปรแกรมปลายทางของคุณ

บางทีสถานที่ที่มีอยู่ถูกเรียกen_US.iso88591และไม่ใช่en_US.latin1อย่างที่ฉันคิด


0

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

ในที่สุดฉันใช้ Filezilla เพื่อเชื่อมต่อเป็นไคลเอนต์ SFTP เรียกดูไฟล์และเปลี่ยนชื่อพวกเขาโดยใช้ GUI Filezilla จัดการตัวอักษรหลบได้ค่อนข้างดี

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