ฉันจะทำให้บริสุทธิ์หรือหนีจากเส้นทางที่ถูกส่งกลับโดย realpath หรือ readlink ได้อย่างไร?


9

realpathและreadlinkส่งคืนพา ธ สัมบูรณ์:

+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome

เส้นทางแบบนี้จัดการได้ง่าย อย่างไรก็ตามสิ่งนี้จะมีปัญหาบางอย่าง:

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่างเช่น:

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นชื่อเช่นนี้จำเป็นต้องได้รับการฆ่าเชื้อเพื่อให้สามารถป้อนไปยังคำสั่งอื่น ๆ usecase อาจเป็นดังนี้:

+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon 

จำเป็นต้องพูดvim $baconจะไม่ทำงานตามที่คาดไว้

ฉันจะทำอย่างไรในการทำให้บริสุทธิ์เส้นทางที่แน่นอนดังนั้นมันจะทำงานร่วมกับคำสั่งอื่น ๆ ?


3
อ้างถึงตัวแปรของคุณเสมอ:vim "$bacon"
steeldriver

@steeldriver ทำไมเป็นแบบนั้น?
Akiva

3
เพราะถ้าคุณไม่ทำคุณจะตกอยู่ในสถานการณ์แบบนี้ :)
terdon

คำตอบ:


12

วิธีการทำเช่นนี้อย่างถูกต้อง

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

$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon

ฉันได้เก็บชื่อไฟล์แปลก ๆ ที่คุณเลือกไว้ ( แม้ว่าฉันจะไม่รู้ว่าทำไมคุณถึงเลือก ) เพื่อความมั่นคง

ทีนี้มากำหนดเส้นทางของpullingATerdonตัวแปรแล้วลองเปิดไฟล์:

$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

ที่ล้มเหลวตามที่คาดไว้ แต่ถ้าตอนนี้เราพูดถูกต้อง:

$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'

มันทำงานได้ตามที่คาดไว้ และใช่คุณยังสามารถเปิดเส้นทางในตัวแก้ไข (เหมาะสม): emacs "$bacon"จะทำงานได้ดี ตกลงดังนั้นจะvimและสิ่งอื่นใด ตัวเลือกการแก้ไขที่คุณโชคร้ายนั้นไม่เกี่ยวข้องกัน


ทำไมคุณล้มเหลว

วิธีที่รวดเร็วในการติดตามสิ่งที่เกิดขึ้นจริงในกรณีของคุณคือการใช้set -x(ปิดอีกครั้งด้วยset +x) ซึ่งทำให้เชลล์พิมพ์คำสั่งแต่ละคำสั่งที่มันจะทำงานก่อนรัน เปิดข้อความการดีบักของเชลล์ด้วยset -x:

$ set -x
$ /bin/ls $bacon 
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

แสดงให้เห็นว่าเราว่าlsกำลังวิ่งสามข้อโต้แย้งเฉพาะกิจการ: '/home/terdon/foo/\e[92mM@r|<', และ'+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'สิ่งนี้เกิดขึ้นเนื่องจากเชลล์ทำการแยกคำและการขยายแบบกลมบนสตริงที่ไม่ได้ระบุ ในกรณีนี้ปัญหาคือการแยกคำเนื่องจากเชลล์เห็นช่องว่างในเส้นทางและอ่านแต่ละสตริงที่คั่นด้วยช่องว่างเป็นอาร์กิวเมนต์แยก

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

$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory

อีกครั้งที่จะพยายามสร้างสามไดเรกทอรีไม่ใช่หนึ่งเนื่องจากการแยกคำ ก่อนอื่นมันสร้าง (สำเร็จ) ไดเรกทอรี/home/terdon/foo/\e[92mM@r|<:

$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'

สร้างไดเรกทอรีที่เรียกว่า+'|'|_e|\|\|0rthในไดเรกทอรีปัจจุบันของคุณได้สำเร็จแล้ว:

$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon    0 Mar 15 00:36  pullingATerdon

[`-_-"]/pullingATerdonและจากนั้นก็พยายามที่จะสร้างไดเรกทอรี สิ่งนี้ล้มเหลวเพราะmkdirตามค่าเริ่มต้นจะไม่สร้างไดเรกทอรีย่อย (สามารถทำได้หากคุณเรียกใช้ด้วย-p):

$ mkdir baz/bar
mkdir: cannot create directory baz/bar’: No such file or directory

เนื่องจากสตริงที่ไม่มีเครื่องหมายอัญประกาศของคุณประกอบด้วย a /, ให้mkdirพิจารณาว่าพา ธ ของสองไดเรกทอรีพยายามค้นหาหนึ่งอันดับแรกและล้มเหลว

นั่นเป็นสาเหตุที่มันล้มเหลว แต่สิ่งที่เกิดขึ้นนั้นซับซ้อนกว่า สตริงที่คุณใช้เป็นจริง glob เปลือกเฉพาะช่วง globซึ่งตรงกับไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันที่มีชื่อเป็นหนึ่งใน 5 ตัวอักษร`, -, หรือ_ "เนื่องจากคุณไม่มีไฟล์ดังกล่าวในไดเรกทอรีปัจจุบันของคุณ glob จึงไม่ตรงกับสิ่งใดเลยและเช่นเดียวกับพฤติกรรมเริ่มต้นใน bash จึงส่งคืนตัวเอง:

$ echo "[\`-_-\"]/pullingATerdon"  ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon'    ## but it echoes the right thing
[`-_-"]/pullingATerdon             ## and matches nothing, so returns itself.

หากต้องการอธิบายให้ชัดเจนนี่คือสิ่งที่จะเกิดขึ้นหากคุณให้รูปกลมที่ตรงกับบางสิ่ง:

$ echo [p]*   ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*

unquoted [p*]มีการขยายไปยังรายการของชื่อไฟล์การจับคู่ (เพียงหนึ่งในกรณีนี้) echoและนั่นคือสิ่งที่ถูกส่งไปยัง อีกเหตุผลที่ทำไมคุณควรพูดทุกสิ่ง

สุดท้ายข้อผิดพลาดจริงที่คุณแสดงนั้นมาจากครั้งที่สองที่คุณรันคำสั่งและล้มเหลวในขั้นตอนแรกเมื่อพยายามสร้าง/home/terdon/foo/\e[92mM@r|<เนื่องจากการเรียกใช้ก่อนหน้านี้ได้สร้างไดเรกทอรีนั้นแล้ว


โดยทั่วไปเมื่อใดก็ตามที่คุณพบว่าตัวเองทำงานกับชื่อไฟล์เองให้ใช้คำสั่ง globs ทุกครั้ง สิ่งนี้:

for file in *; do command "$file"; done

มันจะใช้ได้กับชื่อไฟล์ใด ๆ ไม่ว่าจะเกิดอะไรขึ้นกับการบรรจุ ในตัวอย่างของเราด้านบนคุณสามารถทำได้:

emacs /home/terdon/*92mM*/pullingATerdon

glob ใด ๆ ที่ระบุไฟล์เป้าหมายจะทำเฉพาะ ด้วยวิธีนี้คุณไม่ต้องกังวลกับตัวละครพิเศษและปล่อยให้เชลล์จัดการกับมันได้


ข้อมูลอ้างอิงที่มีประโยชน์บางประการ:

  1. ฉันจะค้นหาและจัดการชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่เว้นวรรคหรือทั้งสองอย่างปลอดภัยได้อย่างไร : หนึ่งในคำถามที่พบบ่อยเกี่ยวกับ Grey Cat's Wiki ที่ยอดเยี่ยม

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

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

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

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