ฉันรู้สึกประหลาดใจเล็กน้อยที่ไม่มีใครพูดถึงเรื่องนี้ แต่คุณสามารถใช้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/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
บางทีสิ่งที่สำคัญกว่านั้นจุดประสงค์หลักของ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
}