ค้นหาพา ธ สัมบูรณ์จากสคริปต์


10

ในสคริปต์ฉันได้รับใน$0เส้นทางญาติที่เป็นไปได้ สำหรับการแปลงให้เป็นสัมบูรณ์ฉันได้พบโซลูชันนี้ซึ่งฉันไม่เข้าใจ:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

ปัญหาของฉันคือภายในมหัศจรรย์ของและ${0%/*} ${0##*/}ดูเหมือนว่าก่อนหน้านี้จะแยก dirname และหลังจะแยกชื่อไฟล์ฉันไม่เข้าใจเลย


2
ใช้การขยายพารามิเตอร์ แต่ไม่ได้ผลสำหรับฉัน หากสคริปต์ของคุณกำลังจะถูกใช้บน Linux เท่านั้นคุณสามารถใช้readlink -f $0เพื่อรับพา ธ แบบบัญญัติ
Shawn J. Goff

1
@Shawn: 1 คะแนนความคิดเห็นที่ยอดเยี่ยมเพราะคุณแนะนำการคิดที่ถูกต้อง: "นั่นใช้การขยายพารามิเตอร์ แต่มันไม่ได้ผลสำหรับฉัน" การใช้dirnameประโยชน์มีประโยชน์ที่นี่
D4RIO

mywiki.wooledge.org/BashFAQ/028และcyberciti.biz/faq/...กล่าวว่าBASH_SOURCEจะดีกว่า$0ในขณะที่$0ช่วยให้ผู้ใช้พิมพ์ลงในคำสั่งซึ่งไม่อาจจะเป็นสคริปต์ในขณะนี้การดำเนินการ
Joel Purra

คำตอบ:


8

คำนิยาม:

${string%substring} ลบที่สั้นที่สุดตรงกับของจากปลาย$substring$string

${string##substring}ลบการแข่งขันที่ยาวที่สุดของจากจุดเริ่มต้นของ$substring$string

ตัวอย่างของคุณ:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} ลบทุกอย่างหลังจากเครื่องหมายทับล่าสุดให้ชื่อไดเรกทอรีของสคริปต์ (ซึ่งอาจเป็นเส้นทางสัมพัทธ์)

${0##*/} ลบทุกอย่างจนถึงเครื่องหมายทับสุดท้ายให้ชื่อของสคริปต์แก่คุณ

ดังนั้นคำสั่งนี้จะเปลี่ยนเป็นไดเรกทอรีของสคริปต์และเชื่อมโยงไดเรกทอรีการทำงานปัจจุบัน (ที่กำหนดโดย$PWD) และชื่อของสคริปต์ที่ให้เส้นทางแบบสัมบูรณ์แก่คุณ

หากต้องการดูสิ่งที่เกิดขึ้นลอง:

echo ${0%/*}
echo ${0##*/}

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

10

Shawn readlink -f $0มีทางออกที่ง่ายที่สุด: หากคุณต้องการแน่ใจว่าจัดการชื่อไฟล์แปลก ๆ อย่างแน่นอนคุณสามารถใช้สิ่งนี้:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

เอกสาร


1
ดีที่เห็นบรรทัดใหม่สุดท้ายถูกจัดการอย่างถูกต้อง น่าเสียดายreadlink -fnเฉพาะ Linux, NetBSD และ OpenBSD
Gilles 'ดังนั้นหยุดความชั่วร้าย'

4

นี่เป็นวิธีที่ปลอดภัยและสามารถอ่านได้มากขึ้นในการทำงานนี้:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

หมายเหตุ:

  • หาก$0เป็นชื่อไฟล์เปลือยที่ไม่มีเส้นทางก่อนหน้าสคริปต์ต้นฉบับจะล้มเหลว แต่ไฟล์ที่ระบุที่นี่จะใช้งานได้ (ไม่ใช่ปัญหา$0แต่อาจอยู่ในแอปพลิเคชันอื่น)
  • วิธีใดวิธีหนึ่งจะล้มเหลวหากเส้นทางไปยังไฟล์ไม่มีอยู่จริง (ไม่ใช่ปัญหา$0แต่อาจอยู่ในแอปพลิเคชันอื่น)
  • unsetเป็นสิ่งสำคัญหากผู้ใช้ของคุณอาจจะมีการCDPATHตั้งค่า
  • ไม่เหมือนreadlink -fหรือrealpathจะใช้กับ Unix เวอร์ชันที่ไม่ใช่ Linux (เช่น Mac OS X)

2

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

basename
dirname

ตัวแรกจะแยกชื่อไฟล์ในขณะที่ตัวที่สองจะแยกพา ธ ดังนั้นถ้าคุณมี $ 0 ให้พูดว่า:

dirname $0

และคุณจะได้รับเส้นทาง

ไชโย


dirname สามารถส่งคืนพา ธ สัมพัทธ์
opticyclic

0

แนะนำ pwd bash builtin พบได้ในแพ็คเกจ GNU coreutils

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.