รับเส้นทางของสคริปต์ปัจจุบันเมื่อดำเนินการผ่าน symlink


58

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

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

ตัวอย่างของโครงสร้าง driectory โดยรวมมีดังนี้:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

ฉันจะอ้างอิงอย่างน่าเชื่อถือได้/usr/local/lib/foo/res/resource_file.txtจากscript.shว่ามันถูกเรียกโดย/usr/local/lib/foo/bin/script.shหรือ~mike/bin/link_to_script?

คำตอบ:


79

ลองใช้วิธีนี้เป็นวิธีแก้ปัญหาทั่วไป:

DIR="$(cd "$(dirname "$0")" && pwd)"

ในกรณีเฉพาะของ symlink ต่อไปนี้คุณสามารถทำได้เช่นกัน:

DIR="$(dirname "$(readlink -f "$0")")"

ทำงานอย่างสมบูรณ์แบบและเป็นวิธีที่ง่ายกว่าสิ่งที่ฉันพยายาม ขอบคุณ!
Mike Deck

@ MikeDeck เพลิดเพลิน โปรดทราบว่าฉันได้แก้ไขปัญหาการอ้างอิงตั้งแต่โพสต์ครั้งแรก ... คุณอาจใช้ตัวเลือกจากการแก้ไขล่าสุดในกรณีที่คุณมีช่องว่างหรือตัวละครแปลกประหลาดอื่น ๆ ในเส้นทางของคุณบางครั้ง แม้ว่ามันจะไม่สำคัญสำหรับโครงการนี้คุณอาจคัดลอกโค้ดจากสคริปต์ของคุณเองตามถนนและมีตัวเลือกที่ดีที่สุดในตอนนั้น!
คาเลบ

1
ฉันควรอธิบายให้ชัดเจนส่วนที่สองทำงานได้อย่างสมบูรณ์ ทางออกแรกที่คุณให้ไม่สามารถใช้งานได้กับ symlink ในระบบของฉัน
Mike Deck

4
@MikeDeck: โซลูชันแรกทำงานสำหรับกรณีทั่วไปของการมีไดเรกทอรีต่าง ๆ ที่เชื่อมโยงเป็นส่วนหนึ่งของเส้นทาง แต่จะไม่ช่วยถ้าไบนารีสุดท้ายคือ symlink นั่นคือสิ่งที่คนที่สองจัดการเพื่อดูแล
Caleb

1
ไม่ทำงานหากไฟล์สคริปต์เป็นsourced (เช่น$ source ./sript.sh) ใช้ได้กับทั้งสองกรณี:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace

7

หนึ่งบรรทัด:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))

2
คำตอบหนึ่งบรรทัดมักจะไม่เป็นประโยชน์มากที่สุด โปรดพิจารณาการขยายคำตอบของคุณเพื่อรวมคำอธิบายลิงก์หรือเอกสารซึ่งสนับสนุนการแก้ไขปัญหาที่แนะนำของคุณเพิ่มเติม
HalosGhost

1
ที่จริงแล้วคุณไม่จำเป็นต้องทำสิ่งนี้คำตอบเดิมของ readlink ทำงานได้ดีถ้าไม่มี symlink ที่เกี่ยวข้องเลย
THESorcerer

3

readlink -f ไม่ได้ผลสำหรับฉันฉันมีข้อผิดพลาดนี้:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

แต่มันก็ใช้ได้ดี:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR

3
แล้วคุณจะอยู่บน Mac และนี้ควรตอบคำถามของคุณ
ไอแซค

ใช่ฉันอยู่บน MacOs @isaac แต่ฉันไม่มีคำถามใด ๆ ฉันโพสต์คำสั่งที่ทำงานด้านข้างของฉัน
Kevin Campion

0

นอกจากนี้หนึ่งเล็กน้อยจากสคริปต์ด้านบน อ็อพชัน -P เพื่อ pwd ติดตาม symlink

DIR="$(cd "$(dirname "$0")" && pwd -P)"

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