ฉันรู้สึกประหลาดใจเล็กน้อยที่ไม่มีใครพูดถึงเรื่องนี้ แต่คุณสามารถใช้readlink -fในการแปลงเส้นทางสัมพัทธ์เป็นเส้นทางที่แน่นอนและเพิ่มลงในเส้นทางดังกล่าว
ตัวอย่างเช่นเพื่อปรับปรุงคำตอบของ Guillaume Perrault-Archambault
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
กลายเป็น
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [ -d "$ARGA" ] && [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
done
}
1. พื้นฐาน - มันทำอะไรได้ดี?
readlink -fคำสั่งจะ (เหนือสิ่งอื่น) แปลงเส้นทางเทียบกับเส้นทางที่แน่นอน สิ่งนี้ช่วยให้คุณทำสิ่งที่ชอบ
$ cd / path / to / my / bin / dir
$ pathappend
$ echo "$ PATH"
<your_old_path> : / path / to / my / bin / dir
2. ทำไมเราทดสอบว่าอยู่ในเส้นทางที่สองหรือไม่
ลองพิจารณาตัวอย่างข้างต้น หากผู้ใช้กล่าวว่า
จากไดเรกทอรีเป็นครั้งที่สอง
จะเป็น แน่นอนว่าจะไม่อยู่ใน แต่แล้วจะถูกตั้งค่า
(เทียบเท่าเส้นทางที่แน่นอนของ) ซึ่งเป็นแล้วใน ดังนั้นเราจึงจำเป็นที่จะต้องหลีกเลี่ยงการเพิ่มที่จะเป็นครั้งที่สองpathappend ./path/to/my/bin/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
บางทีสิ่งที่สำคัญกว่านั้นจุดประสงค์หลักของreadlinkชื่อก็คือการมองไปที่ลิงก์สัญลักษณ์และอ่านชื่อพา ธ ที่มี (กล่าวคือชี้ไปที่) ตัวอย่างเช่น:
$ ls -ld /usr/lib/perl/5.14
-rwxrwxrwx 1 root root Sep 3 2015 /usr/lib/perl/5.14 -> 5.14.2
$ readlink /usr/lib/perl/5.14
5.14.2
$ readlink -f /usr/lib/perl/5.14
/usr/lib/perl/5.14.2
ตอนนี้ถ้าคุณพูดpathappend /usr/lib/perl/5.14และคุณมี/usr/lib/perl/5.14อยู่ในเส้นทางของคุณแล้วก็ไม่เป็นไร เราสามารถทิ้งมันไว้อย่างที่มันเป็น แต่ถ้า/usr/lib/perl/5.14ไม่ได้อยู่ในเส้นทางของคุณเราเรียกreadlinkและได้รับARGA= /usr/lib/perl/5.14.2แล้วเราเพิ่มที่PATHจะ แต่รอสักครู่ - ถ้าคุณอยู่แล้วกล่าวว่าpathappend /usr/lib/perl/5.14แล้วคุณมีอยู่แล้ว/usr/lib/perl/5.14.2ในเส้นทางของคุณและอีกครั้งเราจำเป็นต้องตรวจสอบเพื่อที่จะหลีกเลี่ยงการเพิ่มมันจะPATHเป็นครั้งที่สอง
3. อะไรคือข้อตกลงกับif ARGA=$(readlink -f "$ARG")?
ในกรณีที่ไม่ชัดเจนบรรทัดนี้จะทดสอบว่าreadlinkสำเร็จหรือไม่ นี่เป็นเพียงวิธีการเขียนโปรแกรมที่ดีและป้องกัน หากเรากำลังจะใช้เอาท์พุทจากคำสั่ง m
เป็นส่วนหนึ่งของคำสั่ง n (โดยที่m < n ) ก็ควรระมัดระวังที่จะตรวจสอบว่าคำสั่ง mล้มเหลวและจัดการมันในบางวิธี ฉันไม่คิดว่าเป็นไปได้ที่readlinkจะล้มเหลว - แต่ตามที่กล่าวไว้ในวิธีการเรียกเส้นทางสัมบูรณ์ของไฟล์โดยพลการจาก OS X
และที่อื่น ๆreadlinkเป็นสิ่งประดิษฐ์ของ GNU มันไม่ได้ระบุใน POSIX ดังนั้นความพร้อมใช้งานใน Mac OS, Solaris และ Unixes อื่น ๆ ที่ไม่ใช่ Linux น่าสงสัย (อันที่จริงฉันเพิ่งอ่านความคิดเห็นที่ระบุว่า“readlink -fดูเหมือนจะไม่ทำงานบน Mac OS X 10.11.6 แต่realpathทำงานนอกกรอบได้” ดังนั้นหากคุณอยู่ในระบบที่ไม่มีreadlinkหรือที่readlink -fใช้งานไม่ได้คุณอาจแก้ไขได้ สคริปต์ที่จะใช้realpath) โดยการติดตั้งเครือข่ายความปลอดภัยเราทำให้โค้ดของเราค่อนข้างพกพามากขึ้น
แน่นอนถ้าคุณอยู่ในระบบที่ไม่ได้readlink(หรือ realpath), คุณจะไม่ต้องการที่จะทำpathappend .
การ-dทดสอบครั้งที่สอง( [ -d "$ARGA" ]) อาจไม่จำเป็นจริงๆ ฉันไม่สามารถนึกถึงสถานการณ์ใด ๆ ที่$ARGเป็นไดเรกทอรีและreadlinkประสบความสำเร็จ แต่ $ARGAไม่ใช่ไดเรกทอรี ฉันเพิ่งคัดลอกและวางifคำสั่งแรกเพื่อสร้างคำสั่งที่สามและฉันออกจากการ -dทดสอบที่นั่นด้วยความเกียจคร้าน
4. ความคิดเห็นอื่น ๆ ?
ใช่. เช่นเดียวกับคำตอบอื่น ๆ มากมายที่นี่อันนี้ทดสอบว่าแต่ละอาร์กิวเมนต์เป็นไดเรกทอรีประมวลผลถ้ามันเป็นและไม่สนใจถ้ามันไม่ได้ สิ่งนี้อาจ (หรืออาจไม่) เพียงพอหากคุณใช้pathappend
เฉพาะใน.ไฟล์“” (เช่น.bash_profileและ.bashrc) และสคริปต์อื่น ๆ แต่ดังที่คำตอบนี้แสดงให้เห็น (ด้านบน) มันเป็นไปได้อย่างสมบูรณ์แบบที่จะใช้มันแบบโต้ตอบ คุณจะงงมากถ้าคุณทำ
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
คุณสังเกตเห็นว่าฉันพูดnysql
ในpathappendคำสั่งมากกว่าmysql? และนั่นpathappendไม่ได้พูดอะไรเลย เป็นเพียงการเพิกเฉยต่ออาร์กิวเมนต์ที่ไม่ถูกต้องหรือไม่
ดังที่ฉันได้กล่าวไว้ข้างต้นเป็นวิธีปฏิบัติที่ดีในการจัดการข้อผิดพลาด นี่คือตัวอย่าง:
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ]
then
if [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
else
printf "Error: %s is not a directory.\n" "$ARG" >&2
fi
done
}