ฉันจะแยกตัวแปร $ 0 เพื่อค้นหาไดเรกทอรีและเส้นทางสัมพัทธ์เป็น bash ได้อย่างไร


10

ตัวแปร $ 0 มีข้อมูลเส้นทางของสคริปต์

  • ฉันจะเปลี่ยนข้อมูลเส้นทางเป็นเส้นทางที่แน่นอนได้อย่างไร ฉันหมายถึงวิธีการดำเนินการ ~,., .. หรือคล้ายกัน?
  • ฉันจะแบ่งข้อมูลพา ธ เป็นไดเรกทอรีและชื่อไฟล์ได้อย่างไร

ฉันสามารถใช้ python / perl สำหรับสิ่งนี้ได้ แต่ฉันต้องการใช้ bash ถ้าเป็นไปได้


คุณพยายามทำอะไรให้สำเร็จ BTW การเรียกใช้สคริปต์ด้วย ~ / foo.sh จะขยาย ~ ลงในโฮมไดเร็กตอรี่ของฉันด้วย $ 0 พร้อมกับเวอร์ชั่นทุบตีของฉัน (GNU ทุบตี, เวอร์ชั่น 4.1.5 (2) -release- (x86_64-unknown-linux-gnu)
echox

คำตอบ:


17

คุณไม่จำเป็นต้องดำเนินการสิ่งต่าง ๆ เช่น~เปลือกทำเพื่อคุณ นั่นเป็นเหตุผลที่คุณสามารถส่ง~/filenameต่อไปยังสคริปต์หรือโปรแกรมใดก็ได้และใช้งานได้ - โปรแกรมเหล่านั้นไม่ได้จัดการ~ตัวเองเชลล์ของคุณแปลงอาร์กิวเมนต์ไปยัง/home/username/filenameและส่งต่อไปยังโปรแกรมแทน:

$ echo ~/filename
/home/mrozekma/filename

หากคุณต้องการชื่อไฟล์บัญญัติ (ซึ่งไม่รวมสิ่งที่ชอบ..) ให้ใช้realpath(ขอบคุณนีล ):

$ realpath ~/../filename
/home/filename

สำหรับการแยกเส้นทางออกเป็นชื่อไดเรกทอรีและชื่อไฟล์ให้ใช้dirnameและbasename:

$ dirname /foo/bar/baz
/foo/bar

$ basename /foo/bar/baz
baz

ฉันคิดว่าคุณหมายถึง realpath ไม่ใช่ readlink readlink จะไม่ทำงานในสถานการณ์ทั่วไปเช่นเมื่อลิงก์ใช้เส้นทางสัมพัทธ์และคุณไม่ได้อยู่ใน dir เดียวกับลิงก์
Neil Mayhew

@ Neil realpathดีกว่า แต่readlinkดูเหมือนว่าจะทำงานเมื่อฉันลอง; คุณรู้จากตัวอย่างที่มันล้มเหลว?
Michael Mrozek

1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. ผลตอบแทนfooและrealpathผลตอบแทน/tmp/fooซึ่งเป็นสิ่งที่คุณต้องการ
Neil Mayhew

1
@ Neil, @Michael: readlink -f(หมายเหตุ-f) เกือบเทียบเท่าrealpathและเป็นแบบพกพามากขึ้น: readlink -fใน GNU coreutils และมีอยู่ในระบบอื่น ๆ ด้วยเช่นกัน realpathบรรจุแยกต่างหากและอาจไม่สามารถติดตั้งได้ (เช่นแพ็คเกจที่ไม่ธรรมดาเพียง 5 แพ็คเกจเท่านั้นขึ้นอยู่กับ Ubuntu 10.04 หรือ Debian lenny)
Gilles 'หยุดความชั่วร้าย'

@Gilles: จุดดี ขอบคุณสำหรับการเตือนเกี่ยวกับ realpath -f
Neil Mayhew

5

การใช้ dirname และ basename อย่างที่ Michael พูดถึงควรเป็นวิธีที่ปลอดภัยที่สุดในการได้รับสิ่งที่คุณต้องการ

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

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.

ตัวอย่างนี้นำมาจากคำแนะนำการใช้สคริปต์การทุบตีขั้นสูงซึ่งมีค่าควรดู

คำอธิบายนั้นง่ายมาก:

$ {var # Pattern} ลบออกจาก $ var ส่วนที่สั้นที่สุดของ $ Pattern ที่ตรงกับส่วนหน้าของ $ var $ {var ## Pattern} ลบออกจาก $ var ส่วนที่ยาวที่สุดของ $ Pattern ที่ตรงกับส่วนหน้าของ $ var

ดูรูปแบบเช่น regex และ#หรือ##เป็นตัวดัดแปลงโลภ / ไม่โลภบางชนิด

สิ่งนี้อาจมีประโยชน์หากคุณจะต้องแยกส่วนเส้นทางที่ซับซ้อนมากขึ้น


5
ระวังเมื่อใช้${...##...}และเพื่อนมากกว่าdirnameและbasenameไม่ทำงานในทุกกรณี ยกตัวอย่างเช่นทั้งสอง${0##*/}และ${0%/*}ขยายตัวออกไปเช่นเดียวกับ$0ถ้าไม่ได้มี$0 /
Gilles 'หยุดความชั่วร้าย'

@Gilles ฉันเข้าใจว่าทำไมไม่ได้เป็นทางเลือกที่ดี${0%/*} dirnameอย่างไรก็ตามมีอะไรผิดปกติกับการใช้งาน${0##*/}แทนที่จะเป็นbasenameอย่างไร
toxalot

@toxalot สำหรับหนึ่งนี้ปัญหาเดียวก็คือเมื่อเป็นชื่อไดเรกทอรีที่มีต่อท้าย$0 /แต่ฉันเสียใจคำแนะนำของฉันเพราะdirnameไม่ได้ทำอะไรได้ดีกว่า
Gilles 'หยุดความชั่วร้าย'

2

realpath เป็นคำสั่งที่บอกเส้นทางที่แท้จริง (ลบ .. และลิงค์สัญลักษณ์ ฯลฯ )

เป็นมาตรฐานกับ FreeBSD จากการสนทนานี้ยังมีให้สำหรับ Linux:

http://www.unix.com/shell-programming-scripting/89294-geting-real-path.html

การสนทนานั้นยังเสนอวิธีทุบตี:

$ bash -c "cd /foo/../bar/ ; pwd"

1
สิ่งนี้มักจะใช้งานได้: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Kevin Cantu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.