รายการที่ซ้ำกันใน $ PATH มีปัญหาหรือไม่


45

ฉันแหล่ง bashrc ของเพื่อนของฉันไม่กี่คน ดังนั้นฉันเลยจบลงด้วยการมีรายการซ้ำในตัวแปร $ PATH ของฉัน ฉันไม่แน่ใจว่านี่เป็นปัญหาสำหรับคำสั่งที่ใช้เวลานานในการเริ่มต้นหรือไม่ $ PATH ภายในทำงานอย่างไรในการทุบตี? การมี PATHS มากขึ้นจะทำให้เวลาเริ่มต้นของฉันช้าลงหรือไม่


กองมากเกินพบฉันหมายถึงการเพิ่มองค์ประกอบถึง $ PATH ในทางป้องกันไม่ให้เกิดซ้ำ
dmckee


คำตอบ:


42

การมีรายการเพิ่มเติม$PATHไม่ได้ทำให้การเริ่มต้นของคุณช้าลงโดยตรง แต่จะทำให้ช้าลงทุกครั้งที่คุณเรียกใช้คำสั่งเฉพาะในเชลล์ครั้งแรก (ไม่ใช่ทุกครั้งที่คุณเรียกใช้คำสั่งเนื่องจาก bash รักษาแคชไว้) การชะลอตัวนั้นแทบจะสังเกตไม่ได้เว้นแต่คุณจะมีระบบไฟล์ที่ช้าเป็นพิเศษ (เช่น NFS, Samba หรือระบบไฟล์เครือข่ายอื่น ๆ หรือบน Cygwin)

รายการที่ซ้ำกันก็น่ารำคาญเล็กน้อยเมื่อคุณตรวจสอบ$PATHภาพของคุณคุณต้องลุยผ่าน cruft เพิ่มเติม

ง่ายพอที่จะหลีกเลี่ยงการเพิ่มรายการที่ซ้ำกัน

case ":$PATH:" in
  *":$new_entry:"*) :;; # already there
  *) PATH="$new_entry:$PATH";; # or PATH="$PATH:$new_entry"
esac

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

หมายเหตุด้านข้าง: .bashrcไม่ใช่สถานที่ที่เหมาะสมในการตั้งค่า$PATHหรือตัวแปรสภาพแวดล้อมอื่น ๆ ~/.profileตัวแปรสภาพแวดล้อมควรจะตั้งอยู่ใน ดูไฟล์ติดตั้งใดที่ควรใช้สำหรับตั้งค่าตัวแปรสภาพแวดล้อมด้วย bash , ความแตกต่างระหว่าง. bashrc และ . bash_profile


8
+1: ไม่สามารถเน้นว่า "ให้เพื่อนของคุณสามารถเข้าถึงบัญชีของคุณ" ได้มากพอ แม้ว่าคุณจะไม่ทำอันตราย แต่สคริปต์ของพวกเขาอาจเป็นเพียงสิ่งที่พวกเขาต้องการและยังคงกินอาหารกลางวันของคุณเมื่อคุณจัดหามา
msw

ปัญหาที่เป็นไปได้อย่างหนึ่งของโซลูชันนี้คือถ้า $ new_entry เป็นรายการแรกใน PATH อยู่แล้ว ": $ new_entry:" จะไม่ตรงกัน ฉันแก้ไขสิ่งนี้ในโปรไฟล์ของฉันโดยไม่รวมเครื่องหมายเริ่มต้น ':'
Jeff Bauer

@JeffBauer ฉันไม่เห็นปัญหา ฉันใช้case :$PATH:และไม่case $PATHให้มันเข้าคู่แม้ว่ารายการจะเป็นรายการแรกหรือรายการสุดท้าย
Gilles 'หยุดความชั่วร้าย' ใน

31

ฉันเห็นคนล้างข้อมูลซ้ำจากตัวแปร PATH โดยใช้awkและสิ่งนี้:

PATH=$(printf "%s" "$PATH" | awk -v RS=':' '!a[$1]++ { if (NR > 1) printf RS; printf $1 }')

คุณสามารถลองเพิ่มไฟล์นั้นลงใน bashrc ของคุณเองและตรวจสอบให้แน่ใจว่าคุณได้ไฟล์อื่น ๆ ก่อนที่จะรัน

ทางเลือกที่จะใช้ยูทิลิตี้pathmerge

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

หมายเหตุเกี่ยวกับการรักษาความปลอดภัย:คุณควรจริงๆฟังคำเตือน Gilles'เกี่ยวกับการรักษาความปลอดภัยที่นี่ โดยการหาไฟล์ของผู้ใช้คนอื่นคุณจะให้รหัสผ่านฟรีแก่ผู้ใช้เหล่านั้นเพื่อรันโค้ดของตัวเองในฐานะผู้ใช้ของคุณทุกครั้งที่คุณเริ่มเชลล์ หากคุณไม่ไว้วางใจผู้ใช้เหล่านั้นด้วยรหัสผ่านของคุณคุณไม่ควรจัดหาไฟล์เชลล์ของพวกเขา


6
ฉันชอบ awk one-liner แต่มันพิมพ์ ORS ต่อท้าย ':' ดังนั้นฉันจึงแก้ไขมันเพื่ออ่านPATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986

การลาก:ไม่ใช่แค่เรื่องเครื่องสำอาง มันเหมือนกับการเพิ่ม.เส้นทางของคุณซึ่งอาจเป็นอันตราย
wisbucky

ฉันได้แก้ไขคำตอบเพื่อรวมการแก้ไขจาก gkb0986
Tim Lesher

@TimLesher เหตุผลที่ฉันไม่เคยแก้ไขกว่าลงในคำตอบก็คือว่ามันไม่ทำงานสำหรับฉัน .... และเป็นต้นฉบับโดยไม่ต้องมันไม่ทำงาน (รวมทั้งไม่ได้ออกจากแยกต่อท้าย. ผมไม่ทราบว่าสิ่งที่แตกต่างคือ .
คาเลบ

1
@ gkb0986 โซลูชันนี้ยังคงล้มเหลวหากเส้นทางมีช่องว่างที่หลบหนีเช่น PATH = / bin: / foo \ bar: / usr / bin ฉันพบตัวแปรที่หลีกเลี่ยงสิ่งนี้ได้ที่unix.stackexchange.com/a/124517/106102
maharvey67

13

จากคำตอบของ @Gilles คุณสามารถสรุปได้ในฟังก์ชั่นเพื่อลดการพิมพ์:

function addToPATH {
  case ":$PATH:" in
    *":$1:"*) :;; # already there
    *) PATH="$1:$PATH";; # or PATH="$PATH:$1"
  esac
}

addToPATH /Applications/AIRSDK_Compiler/bin
addToPATH ~/.local/lib/npm/bin

1
ส่วนใหญ่คำตอบที่ใช้งานได้จริง (ระดับสูงอาจ)
ijoseph

3

มีการดำเนินการจับคู่ครั้งแรกเท่านั้น$PATHดังนั้นรายการที่ตามมาจะไม่ถูกประมวลผลหลังจากนั้น นั่นเป็นเหตุผลที่บางครั้งคุณควรแก้ไขลำดับของรายการในของคุณ$PATHเพื่อให้สภาพแวดล้อมของคุณทำงานตามที่คาดไว้

หากต้องการตอบคำถามของคุณ: สิ่งนี้ไม่ควรเป็นสาเหตุของการเริ่มต้นช้า


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

@balki คุณหมายถึงการทำคำสั่งด้วยTABหรือไม่? complete -c which -aในกรณีที่คุณควรตรวจสอบว่าคุณหมายที่สมบูรณ์ดูไม่เหมือน คุณควรลบ-aพารามิเตอร์ complete | grep whichคุณสามารถตรวจสอบว่าโดยการออกคำสั่ง:
Rajish

มันอาจยังคงเป็นปัญหาหากค้นหาไดเรกทอรีเดียวกันซึ่งไม่ได้อยู่หลายครั้งก่อนค้นหา
Random832

-1

เพื่อป้องกันรายการที่ซ้ำกันใน PATH ของฉันฉันต้องใส่สิ่งต่อไปนี้ในทั้งสอง ~ / .bash_profile และ ~ / .bashrc:

PATH=$(echo $(sed 's/:/\n/g' <<< $PATH | sort | uniq) | sed -e 's/\s/':'/g')

ข้อเสียเปรียบหลักคือมันเรียงลำดับรายการ PATH แต่ฉันคิดว่าฉันสามารถอยู่กับมันได้


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