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


15

ขออภัยถ้านี่มีคำตอบที่อื่นฉันไม่ทราบวิธีค้นหาปัญหาของฉัน

ฉันใช้การจำลองบางอย่างบนเซิร์ฟเวอร์ linux HPC redhat และรหัสของฉันสำหรับการจัดการโครงสร้างโฟลเดอร์เพื่อบันทึกผลลัพธ์มีข้อผิดพลาดที่โชคร้าย รหัส matlab ของฉันเพื่อสร้างโฟลเดอร์คือ:

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

ที่sp.run_numberเป็นจำนวนเต็ม ฉันลืมแปลงเป็นสตริง แต่ด้วยเหตุผลบางอย่างที่ทำงานmkdir(folder);(ใน matlab) ยังคงประสบความสำเร็จ ในความเป็นจริงการจำลองวิ่งโดยไม่มีการผูกปมและข้อมูลถูกบันทึกลงในไดเรกทอรีที่ตรงกัน

ตอนนี้เมื่อโครงสร้างโฟลเดอร์ถูกสอบถาม / พิมพ์ฉันได้รับสถานการณ์ต่อไปนี้:

  • เมื่อฉันพยายามแท็บเติมข้อความอัตโนมัติ: run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • เมื่อฉันใช้ls: run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?.
  • เมื่อฉันถ่ายโอนไปยัง mac ของฉันโดยใช้ rsync --progressตัวเลือกจะแสดง: run_\#003/ฯลฯ ด้วย (ฉันถือว่า) ตัวเลขที่ตรงกับจำนวนเต็มเป็นsp.run_numberเบาะสามหลักดังนั้นการวิ่งครั้งที่ 10 คือrun_\#010/
  • เมื่อฉันดูโฟลเดอร์ใน Finder ฉันเห็น run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • ดูคำถามนี้และใช้คำสั่งls | LC_ALL=C sed -n lฉันได้รับ:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

ฉันไม่สามารถจัดการcdลงในโฟลเดอร์โดยใช้การรับรองเหล่านี้

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


4
"เมื่อฉันพยายามแท็บเติมข้อความอัตโนมัติ: ... ถ้าฉันลองพิมพ์ ... " ทำไมพิมพ์และไม่ปล่อยให้การเติมข้อความอัตโนมัติสมบูรณ์ถ้าคุณต้องการ นอกจากนี้ยัง^Aไม่ได้^ตามตัวอักษรAแต่ Ctrl-A (คุณสามารถพิมพ์โดยใช้ Ctrl-V Ctrl-A เนื่องจาก Ctrl-A โดยทั่วไปจะเป็นทางลัดสำหรับเชลล์)
muru

@muru ที่ใช้งานไม่ได้ ... ฉันไปถึงrun_แล้วและฉันต้องพิมพ์บางอย่าง
Phill

ขออภัยแสดงความคิดเห็นก่อนที่จะเห็นการแก้ไขของคุณที่จะได้รับฉันผ่านทาง cd
Phill


9
BTW ที่ "ด้วยเหตุผลบางอย่าง" ทำไม mkdir ใน MATLAB ทำอย่างนี้เป็นเพราะเพียงตัวอักษรที่ไม่ถูกต้องในชื่อแฟ้มหรือไดเรกทอรีบนระบบไฟล์ยูนิกซ์เป็น NUL /และคาดการณ์ล่วงหน้าเฉือน อักขระอื่น ๆ ที่ถูกต้องรวมถึงตัวควบคุม ฉันไม่ทราบว่า matlab จะทำอะไรถ้า sp.run_number เป็น 0 (อาจยกเลิกด้วยข้อผิดพลาดหรือการผลิตrun_เนื่องจากไบต์ NUL จะยุติสตริงชื่อไดเรกทอรี) แน่นอนว่านี่จะเป็นปัญหาสำหรับค่า 16- บิต (หรือสูงกว่า) ที่มี NUL byte อยู่และจะแตกต่างกันไปตาม endian-ness ของระบบที่ใช้งาน matlab
cas.

คำตอบ:


26

คุณสามารถใช้renameยูทิลิตี้Perl (aka prenameหรือfile-rename) เพื่อเปลี่ยนชื่อไดเรกทอรี

หมายเหตุ:สิ่งนี้ไม่ให้สับสนกับrenameจากutil-linuxหรือรุ่นอื่น ๆ

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

ใช้ord()ฟังก์ชันของ perl เพื่อแทนที่แต่ละอักขระควบคุมในชื่อไฟล์ด้วยหมายเลขลำดับสำหรับอักขระนั้น เช่น^Aกลายเป็น 1, ^Bกลายเป็น 2, ฯลฯ

-nตัวเลือกสำหรับแห้งวิ่งเพื่อแสดงสิ่งที่rename จะทำอย่างไรถ้าคุณปล่อยให้มัน ลบออก (หรือแทนที่ด้วย-vสำหรับเอาต์พุต verbose) เพื่อเปลี่ยนชื่อจริง

โมดิeฟายเออร์ในการs/LHS/RHS/egดำเนินการทำให้ perl ดำเนินการ RHS (การแทนที่) เป็นรหัส perl และ$1ข้อมูลที่ตรงกัน (อักขระควบคุม) จาก LHS

หากคุณต้องการหมายเลขศูนย์เบาะในชื่อไฟล์ที่คุณสามารถรวมกับord() sprintf()เช่น

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

ตัวอย่างข้างต้นใช้งานได้ถ้าหาก sp.run_numberในสคริปต์ matlab ของคุณอยู่ในช่วง 0..26 (ดังนั้นจึงสร้างอักขระควบคุมในชื่อไดเรกทอรี)

ในการจัดการกับอักขระ 1 ไบต์ใด ๆ (เช่นจาก 0..255) คุณต้องใช้:

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

ถ้าsp.run_numberอาจจะ> 255 คุณจะต้องใช้ของ Perl ฟังก์ชั่นแทนunpack() ord()ฉันไม่รู้ว่า matlab แสดงผล int ที่ไม่กลับด้านในสตริงได้อย่างไรดังนั้นคุณจะต้องทดสอบ ดูperldoc -f unpackรายละเอียดที่

เช่นข้อมูลต่อไปนี้จะแกะค่าที่ไม่ได้ลงชื่อทั้ง 8 บิตและ 16 บิตและ zero-pad ให้กว้าง 5 หลัก:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/

ขอบคุณสำหรับรายละเอียด! ฉันพยายามที่จะทดสอบมันออกมาพร้อมกับ-nตัวเลือก แต่ก็บอกฉันเป็นตัวเลือกที่ไม่ถูกต้องของ - ข้อมูลรุ่นให้ฉันrename from util-linux 2.23.2เพื่อ I'mnot แน่ใจว่าฟังก์ชั่นเดียวกัน
Phill

3
นั่นเป็นเหตุผลที่ฉันระบุเวอร์ชันของยูทิลิตี้ perl 's แตกต่างกันมากน้อยให้ห่างไกลที่มีความสามารถและตัวเลือกบรรทัดคำสั่งเข้ากันไม่ได้ หากคุณใช้เดเบียนหรือคล้ายกันลองติดตั้งแพคเกจ มิฉะนั้นให้ติดตั้งแพ็คเกจที่เหมาะสมสำหรับ distro ของคุณ มันอาจจะถูกติดตั้งไว้แล้วลองเรียกใช้หรือแทนเพียง renameutil-linuxrenamefile-renameprenamefile-renamerename
cas

ใช่ฉันคิดว่าเป็นกรณี ฉันจะดูว่าฉันจะได้รับหนึ่งในผู้ที่ทำงาน ขอขอบคุณอีกครั้งที่สละเวลาเพื่อช่วยเหลือฉัน!
Phill

11

และฉันคิดว่าเพื่อความอยากรู้อยากเห็นสิ่งนี้เกิดขึ้นได้อย่างไรในครั้งแรก?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

ที่sp.run_numberเป็นจำนวนเต็ม ฉันลืมแปลงเป็นสตริง แต่ด้วยเหตุผลบางอย่างทำงานmkdir(folder); (ใน matlab) ยังคงประสบความสำเร็จ

ดังนั้นจะปรากฏว่าmkdir([...])ใน Matlab เชื่อมต่อสมาชิกของอาร์เรย์เพื่อสร้างชื่อไฟล์เป็นสตริง แต่คุณให้ตัวเลขแทนและตัวเลขเป็นตัวอักษรในคอมพิวเตอร์จริงๆ ดังนั้นเมื่อsp.run_numberเป็น1มันทำให้คุณตัวละครที่มีค่า1แล้วตัวละครที่มีค่า2อื่น ๆ

นั่นคือตัวควบคุมพวกเขาไม่มีสัญลักษณ์ที่พิมพ์ได้และการพิมพ์บนเทอร์มินัลจะมีผลกระทบอื่น ๆ ดังนั้นแทนที่จะพวกเขากำลังมักจะแสดงโดยประเภทที่แตกต่างกันของหนี: \001(ฐานแปด) \x01(Hex) มีทั้งหมดแสดงทั่วไปสำหรับตัวละครที่มีค่า^A 1อักขระที่มีค่าศูนย์แตกต่างกันเล็กน้อยเป็นไบต์ของ NUL ที่ใช้เพื่อทำเครื่องหมายจุดสิ้นสุดของสตริงใน C และในการเรียกระบบ Unix

หากคุณไปสูงกว่า 31 คุณจะเริ่มเห็นตัวอักษรที่พิมพ์ได้ 32 คือช่องว่าง (ไม่ปรากฏให้เห็นมากนัก), 33 = !, 34 = "เป็นต้น

ดังนั้น,

  • run_ run_^A/ run_^B/- อันแรกrun_สอดคล้องกับอันที่มีศูนย์ไบต์สตริงจะจบลงที่นั่น คนอื่น ๆ ^Aที่แสดงให้เห็นว่าเปลือกของคุณชอบที่จะใช้แสดงรหัสควบคุมด้วย สัญกรณ์ยังบอกเป็นนัยถึงความจริงที่ว่าถ่านที่มีค่าตัวเลข 1 สามารถป้อนได้Ctrl-Aแม้ว่าคุณจะต้องบอกให้เชลล์ตีความว่าไม่ใช่อักขระควบคุม แต่เป็นตัวอักษรCtrl-V Ctrl-Aควรทำอย่างน้อยใน Bash

  • ls: run_ run_? run_?- lsไม่ชอบพิมพ์ตัวอักษรที่ไม่สามารถพิมพ์ได้บนเครื่อง แต่มันจะแทนที่ด้วยเครื่องหมายคำถาม

  • rsync: run_\#003/- นั่นเป็นสิ่งใหม่สำหรับฉัน แต่ความคิดนั้นเหมือนกันแบ็กสแลชทำเครื่องหมายการหลบหนีและส่วนที่เหลือเป็นค่าตัวเลขของตัวละคร \003มันดูเหมือนว่าฉันว่าจำนวนที่นี่อยู่ในฐานแปดเหมือนกันมากขึ้น

  • ใช้คำสั่งls | LC_ALL=C sed -n l... run_\006$ run_\a$ run_\b$ run_\t$- \a, \bและ\tมี C หนีการปลุก (ระฆัง) Backspace และแท็บตามลำดับ พวกเขามีค่าตัวเลข 7, 8 และ 9 \006ดังนั้นจึงควรมีความชัดเจนว่าทำไมพวกเขามาหลังจากที่ การใช้การหลบหลีก C เหล่านี้เป็นอีกวิธีในการทำเครื่องหมายอักขระควบคุม เครื่องหมายดอลลาร์ต่อท้ายทำเครื่องหมายบรรทัดสิ้นสุด

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

ตัวเลือกใดเป็นตัวแทนที่ถูกต้องของโฟลเดอร์

ทั้งหมดในแง่ ...

ใน Bash คุณสามารถใช้\000และ\x00Escape ใน $'...'เครื่องหมายคำพูดเพื่อแทนอักขระพิเศษดังนั้น$'run_\033(octal) หรือ$'run_\x1b'สอดคล้องกับไดเรกทอรีที่มีค่าอักขระ 27 (ซึ่งเป็น ESC) (ฉันไม่คิดว่า Bash รองรับการหลบหนีด้วยตัวเลขทศนิยม)

คำตอบของ cas มีสคริปต์ในการเปลี่ยนชื่อเหล่านั้นดังนั้นฉันจะไม่ไปที่นั่น


หากเป็น GNU lsจะมีตัวเลือกการอ้างถึงบางอย่างรวมถึง-b/ --escapeและ--quoting-style=หรือQUOTING_STYLEตัวแปรสภาพแวดล้อมเพื่อควบคุมวิธีแสดงอักขระที่ไม่พิมพ์ ฉันไม่คิดว่าจะมีตัวเลือกที่จะทำให้มันชอบทางแปดของเวอร์ชั่นตัวละคร
Toby Speight

3

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

เพื่อหลีกเลี่ยงการชนกันระหว่างชื่อที่มีอยู่ให้ใช้โฟลเดอร์ปลายทางอื่น

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

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

โชคดี!

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