ฉันจะดึงชื่อไฟล์สัมบูรณ์ในเชลล์สคริปต์บน Mac OS X ได้อย่างไร


19

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

บน Linux ดูเหมือนว่าจะทำเช่นนี้:

$(readlink -mn "$0")

แต่readlinkดูเหมือนว่าจะทำงานแตกต่างกันมากใน Mac OS X

ฉันอ่านแล้วว่านี่ใช้เสร็จแล้ว

$(realpath $0)

ใน BSD แต่ก็ไม่ได้ผลเช่นกัน Mac OS X realpathไม่ได้

ความคิดใด ๆ


1
ดูคำถามนี้ใน SO: stackoverflow.com/questions/799679/…
Telemachus

3
และอันนี้: stackoverflow.com/questions/1055671/ …
Telemachus

คำตอบ:


19

ฉันโกงและใช้ perl สำหรับสิ่งนี้:

#!/bin/bash
dirname=`perl -e 'use Cwd "abs_path";print abs_path(shift)' $0`
echo $dirname

คุณคิดว่าฉันแค่เขียนสคริปต์ทั้งหมดเป็นภาษา Perl และบ่อยครั้งที่ฉันทำ แต่ไม่เสมอไป


งานนี้ขอบคุณมาก ฉันจะให้คุณโหวตทันทีที่ฉันสามารถ ไม่มีใครมีวิธี "เปลือกบริสุทธิ์" ในการทำเช่นนี้?
Huxi

1
ฉันเกรงว่าจะดีเท่าที่จะได้รับ (ที่ได้รับความหลายหลายบรรทัด "หอยบริสุทธิ์" แฮ็หนึ่งสามารถหาใน Google.)
Arjan

ความเป็นไปได้อื่น (แม้ว่าน่าเกลียด) คือการข้ามเส้นทาง '.. ' การท่องจำ (ผ่านการเรียกซ้ำหรืออาเรย์) จนกระทั่ง '.. ' ส่งคืนไฟล์เดียวกันกับที่คุณเพิ่งมี (เช่น: คุณอยู่ด้านบน) จากนั้นกลับมาประกอบ เส้นทางที่คุณไป ฉันเคยเห็นซอฟต์แวร์การสำรองข้อมูล Networker ของ Legato ทำเช่นนี้ในระหว่างการ strace เพื่อให้ได้เส้นทางที่ 'จริง' (แต่อาจไม่แน่นอน) แต่มันจะเป็นรหัสมากกว่าข้างต้น
ericslaw

ไม่แน่ใจว่าทำไมมีคนดัดแปลงรหัสเพื่อใช้ $ 1 แทน $ 0 $ 1 ไม่ใช่อาร์กิวเมนต์แรกของสคริปต์ทุบตีหรือไม่ ฉันต้องการเส้นทางไปยังสคริปต์การดำเนินการทุบตีไม่ใช่อาร์กิวเมนต์แรก
ericslaw

27
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"

ทำงานใน MacOSX ด้วย
Alexar

1
นี่มันสุดยอดมาก! มีคำตอบที่ซับซ้อนเกินกว่าจำนวนมากลอยอยู่รอบ ๆ
Jason S

3
ใช้งานได้กับไฟล์ในไดเรกทอรี symlinked เท่านั้นไม่ใช่ไฟล์ symlinked ทั่วไป
Gerhard Burger

1
นอกจากนี้ยังมีประโยชน์กับunset -v CDPATHก่อนซีดีเนื่องจากซีดีอาจทำให้เกิดผลลัพธ์ที่ไม่ต้องการหากตั้งค่า CDPATH
Bile Phile

เพื่อจัดการอย่างน้อยเลเยอร์เดียวของการเชื่อมโยงของไฟล์คุณสามารถทดสอบในวิธีที่เข้ากันได้กับ readlink (macs ไม่มี -f): scriptDir=$(unset -v CDPATH; cd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE)")" && pwd -P)
Binary Phile

0

วิธีนี้จะจัดการกับคอมโบของ symlink และทำงานกับไฟล์และโฟลเดอร์:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

แต่มันไม่สนับสนุนความสัมพันธ์แบบเรียลไทม์ เรื่องนี้จะต้องแปลง อธิบายไว้ที่นี่


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