วิธีที่สะดวกสบายมากขึ้นในการแก้ไข $ PATH แบบยาวหรือไม่


35

ฉันต้องการเพิ่มใน ~ / .bashrc บางไดเรกทอรีไปยัง $ PATH ของฉัน

$ PATH ของฉันค่อนข้างยาวดังนั้นจึงเป็นการยากที่จะดูว่าไดเรกทอรีใดที่มีอยู่และเรียงตามลำดับ

ฉันรู้ว่าฉันสามารถแก้ไข ~ / .bashrc เป็น:

PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...

มันทำให้อ่านง่ายขึ้น แต่ฉันสงสัยว่าในช่วงปีที่ผ่านมา Bash ได้รับไวยากรณ์บางอย่างที่ทำให้การระบุ PATH นั้นง่ายขึ้นหรือไม่ เช่นฉันประหลาดใจเกี่ยวกับไวยากรณ์คล้ายกับ:

PATH=:((
  /some/dir
  /another/dir
  /yet/another
  /and/another
  ...
))

ฉันรู้ว่าไวยากรณ์ดังกล่าวไม่ถูกต้อง ฉันสงสัยว่ามีบางอย่างที่ง่าย มีอะไรบ้าง


แบบดั้งเดิมกวดวิชาเพื่อกำหนดเส้นทางผ่านPATH=foo:$PATHดูเหมือนว่าผิดเพราะมันให้การเจริญเติบโตทุกครั้งsource ~/.bashrcและยังexec bashไม่สามารถช่วยตั้งแต่เป็น$PATH export
林果皞

คำตอบ:


25

ฉันใช้ชุดฟังก์ชั่นอำนวยความสะดวกสำหรับการเพิ่มหรือต่อท้ายพา ธ ไปยังตัวแปร ฟังก์ชั่นมาใน tarball แจกจ่ายสำหรับ Bash ในไฟล์ contrib ชื่อ "pathfuncs"

  • add_path จะเพิ่มรายการที่ส่วนท้ายของตัวแปร PATH
  • pre_path จะเพิ่มรายการไปยังจุดเริ่มต้นของตัวแปร PATH
  • del_path จะลบรายการออกจากตัวแปร PATH ไม่ว่าจะอยู่ที่ใด

หากคุณระบุตัวแปรเป็นอาร์กิวเมนต์ที่สองมันจะใช้มันแทน PATH

เพื่อความสะดวกนี่คือ:

# is $1 missing from $2 (or PATH) ?
no_path() {
    eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

หากคุณเพิ่มสิ่งเหล่านี้ลงในไฟล์ bash startup ของคุณคุณสามารถเพิ่มใน PATH ดังนี้:

pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin

หรือระบุตัวแปรอื่น:

pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH

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

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


ขอบคุณ ฉันตรวจสอบรหัสของคุณแล้วและใช้งานได้ น่าแปลกที่ฉันพบการใช้งานสำหรับ del_path (A "." คืบคลานเข้าสู่เส้นทางของฉันในบางสถานการณ์มารรู้จากที่ใดดังนั้นฉันจึงทำdel_path .)
Niccolo M.

สวัสดี เป็นไปได้ที่จะแหล่งที่มา (รวม) pathfuncs นี้จากสคริปต์ bashrc หรือฉันควรคัดลอก / วางพวกเขาไปที่นั่น?
Cristiano

@Cristiano ทั้งสองจะทำงาน มันขึ้นอยู่กับคุณจริงๆ
ปลาดาว

11

ตกลงฉันหาวิธีแก้ปัญหาต่อไปนี้ซึ่งฉันคิดว่ามันดี (เท่าที่เชลล์เชลล์ไป) มันใช้ไวยากรณ์อาร์เรย์ของ Bash และยังเป็นวิธีที่เรียบร้อยในการเข้าร่วมองค์ประกอบ:

paths=(
  /some/dir
  /another/dir
  '/another/dir with spaces in it'
  /yet/another
  /and/another
  /end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )

PATH=$paths_joined:$PATH

แจ้งเตือน!

ปรากฎว่าโซลูชันนี้มีปัญหา : ซึ่งแตกต่างจากโซลูชันของ @terdon และ @Starfish มันไม่ได้ตรวจสอบก่อนว่าเส้นทางนั้นมีอยู่แล้วใน PATH หรือไม่ ดังนั้นเนื่องจากฉันต้องการใส่รหัสนี้ใน ~ / .bashrc (และไม่อยู่ใน ~ / .profile) เส้นทางที่ซ้ำกันจะคืบคลานเข้าสู่ PATH ดังนั้นอย่าใช้วิธีแก้ปัญหานี้ (เว้นแต่คุณจะใส่ไว้ใน ~ / .profile (หรือดีกว่า ~ / .bash_profile เนื่องจากมีไวยากรณ์ของ Bash เฉพาะ)


1
ดีมาก. คุณช่วยตอบรับคำตอบให้คนอื่นไม่ได้มาที่นี่เพื่อเสนอทางออกเมื่อคุณเจอแล้ว? ขอบคุณ
Basic

เส้นทางที่ซ้ำกันไม่ใช่ปัญหาจริงๆ ไม่น่าเป็นไปได้สูงที่คุณจะต้องเพิ่มไดเรกทอรีให้เพียงพอPATHเพื่อก่อให้เกิดปัญหาด้านประสิทธิภาพ (โดยเฉพาะอย่างยิ่งเมื่อเชลล์ทำการค้นหาสำเร็จ)
chepner

5

~/.bashrcฉันจะใช้ฟังก์ชั่นด้านล่างในของฉัน มันเป็นสิ่งที่ฉันได้รับจากการดูแลระบบในแล็บเก่าของฉัน แต่ฉันไม่คิดว่าเขาจะเขียนมัน เพียงเพิ่มบรรทัดเหล่านี้ในของคุณ~/.profileหรือ~/.bashrc:

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

มีข้อดีหลายประการ:

  • การเพิ่มไดเรกทอรีใหม่ลงใน$PATHนั้นเป็นเรื่องเล็กน้อย: pathmunge /foo/bar;
  • มันหลีกเลี่ยงรายการที่ซ้ำกัน;
  • คุณสามารถเลือกได้ว่าจะเพิ่มรายการใหม่ที่จะเริ่มต้น ( pathmunge /foo/barหรือจุดสิ้นสุด ( pathmunge /foo/barหลัง) $PATHของ

ไฟล์เริ่มต้นเชลล์ของคุณจะมีสิ่งต่อไปนี้:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end

ขอบคุณ แต่ผมจะเลือกวิธีการแก้ปัญหา @ grepปลาดาวเพราะเขาไม่ได้วางไข่
Niccolo M.

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

โปรดทราบว่าฟังก์ชั่นที่เร็วกว่านั้นมีอยู่ใน redhat โดยไม่ต้องใช้คำสั่งภายนอกgrepดูbugzilla.redhat.com/show_bug.cgi?id=544652#c7
林果皞

4

ฉันต้องการเพิ่มใน ~ / .bashrc บางไดเรกทอรีไปยัง $ PATH ของฉัน

ฉันใช้สิ่งต่อไปนี้ใน Cygwin ควรทำงานใน bash รุ่นอื่น คุณสามารถลบสิ่งที่unset PATHต้องสร้างในปัจจุบันของคุณPATH(ถ้าคุณทำเช่นนี้คุณอาจต้องคิดวิธีการเพิ่ม:ตัวคั่นอย่างถูกต้อง)

บันทึก:

  • ฉันเคยมีฟังก์ชั่นนี้ในbashฟังก์ชั่น แต่มันหายไปหลังจากความผิดพลาดของดิสก์

ในของฉัน.bash_profile:

# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do 
  PATH="${PATH}$line"; 
done < ~/.path_elements

...

# Add current directory to path
export PATH=".:${PATH}"

ใน~/.path_elements:

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows

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

1

ฉันใช้สิ่งนี้ใน. bashrc ของฉัน (และ. zshrc ของฉันด้วยเนื่องจากโดยปกติฉันจะใช้ zsh หากมีให้ใช้แทนการทุบตี) ได้รับมันต้องการให้ฉันเพิ่มไดเรกทอรีด้วยตนเอง แต่ข้อดีคือเมื่อฉันอัปเดตฉันสามารถคัดลอกไปยังเซิร์ฟเวอร์ใหม่และไม่ต้องกังวลกับ PATH บนเซิร์ฟเวอร์ใหม่ที่สร้างขึ้นด้วยไดเรกทอรีที่ไม่มีอยู่จริง

##
## PATH
##
## แทนที่จะเป็นเพียงการบดบังเส้นทางของเราด้วยไดเรกทอรีที่อาจ
## ไม่เหมาะสมกับเซิร์ฟเวอร์นี้พยายามฉลาดเกี่ยวกับสิ่งที่เราเพิ่ม
##
PATH = / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin
[-d / cs / sbin] && PATH = / cs / sbin: $ PATH
[-d / cs / bin] && PATH = / cs / bin: $ PATH
[-d / usr / ucb] && PATH = $ PATH: / usr / ucb
[-d / usr / ccs / bin] && PATH = $ PATH: / usr / ccs / bin
[-d / usr / local / ssl / bin] && PATH = $ PATH: / usr / local / ssl / bin
[-d / usr / krb5 / bin] && PATH = $ PATH: / usr / krb5 / bin
[-d / usr / krb5 / sbin] && PATH = $ PATH: / usr / krb5 / sbin
[-d / usr / kerberos / sbin] && PATH = $ PATH: / usr / kerberos / sbin
[-d / usr / kerberos / bin] && PATH = $ PATH: / usr / kerberos / bin
[-d /cs/local/jdk1.5.0/bin] && PATH = $ PATH: /cs/local/jdk1.5.0/bin
[-d /usr/java/jre1.5.0_02/bin] && PATH = $ PATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/bin] && PATH = $ PATH: /usr/java1.2/bin
[-d /cs/local/perl5.8.0/bin] && PATH = $ PATH: /cs/local/perl5.8.0/bin
[-d / usr / perl5 / bin] && PATH = $ PATH: / usr / perl5 / bin
[-d / usr / X11R6 / bin] && PATH = $ PATH: / usr / X11R6 / bin
[-d / etc / X11] && PATH = $ PATH: / etc / X11
[-d / opt / sfw / bin] && PATH = $ PATH: / opt / sfw / bin
[-d / usr / local / apache / bin] && PATH = $ PATH: / usr / local / apache / bin
[-d / usr / apache / bin] && PATH = $ PATH: / usr / apache / bin
[-d / cs / admin / bin] && PATH = $ PATH: / cs / admin / bin
[-d / usr / openwin / bin] && PATH = $ PATH: / usr / openwin / bin
[-d / usr / xpg4 / bin] && PATH = $ PATH: / usr / xpg4 / bin
[-d / usr / dt / bin] && PATH = $ PATH: / usr / dt / bin

ฉันทำสิ่งเดียวกันกับ MANPATH ของฉัน:

##
## MANPATH
##
## แทนที่จะเพียงแค่อุดตัน MANPATH ของเราด้วยไดเรกทอรีที่อาจ
## ไม่เหมาะสมกับเซิร์ฟเวอร์นี้พยายามฉลาดเกี่ยวกับสิ่งที่เราเพิ่ม
##
MANPATH = / usr / คน / ท้องถิ่น
[-d / usr / share / man] && MANPATH = $ MANPATH: / usr / share / man
[-d / usr / local / share / man] && MANPATH = $ MANPATH: / usr / local / share / man
[-d / usr / man] && MANPATH = $ MANPATH: / usr / man
[-d / cs / man] && MANPATH = $ MANPATH: / cs / man
[-d / usr / krb5 / man] && MANPATH = $ MANPATH: / usr / krb5 / man
[-d / usr / kerberos / man] && MANPATH = $ MANPATH: / usr / kerberos / man
[-d / usr / local / ssl / man] && MANPATH = $ MANPATH: / usr / local / ssl / man
[-d /cs/local/jdk1.5.0/man] && MANPATH = $ MANPATH: /cs/local/jdk1.5.0/man
[-d /usr/java/jre1.5.0_02/man] && MANPATH = $ MANPATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/man] && MANPATH = $ MANPATH: /usr/java1.2/man
[-d / usr / X11R6 / man] && MANPATH = $ MANPATH: / usr / X11R6 / คน
[-d / usr / local / apache / man] && MANPATH = $ MANPATH: / usr / local / apache / man
[-d / usr / local / mysql / man] && MANPATH = $ MANPATH: / usr / local / mysql / man
[-d /cs/local/perl5.8.0/man] && MANPATH = $ MANPATH: /cs/local/perl5.8.0/man
[-d / usr / perl5 / man] && MANPATH = $ MANPATH: / usr / perl5 / man
[-d / usr / local / perl / man] && MANPATH = $ MANPATH: / usr / local / perl / man
[-d /usr/local/perl5.8.0/man] && MANPATH = $ MANPATH: /usr/local/perl5.8.0/man
[-d / usr / openwin / man] && MANPATH = $ MANPATH: / usr / openwin / man

นอกเหนือจากการมีไฟล์เดียวที่ฉันสามารถคัดลอกไปยังระบบในสภาพแวดล้อมที่แตกต่างกันโดยไม่ต้องกลัวว่าจะเพิ่มไดเรกทอรีที่ไม่มีอยู่ใน PATH วิธีนี้ยังมีข้อดีของการอนุญาตให้ฉันระบุลำดับที่ฉันต้องการให้ไดเรกทอรีปรากฏใน PATH เนื่องจากบรรทัดแรกของแต่ละคำนิยามนิยามตัวแปร PATH ใหม่อย่างสมบูรณ์ฉันสามารถอัปเดต. bashrc และแหล่งที่มาได้หลังจากการแก้ไขเพื่อให้เชลล์ของฉันอัปเดตโดยไม่ต้องเพิ่มรายการที่ซ้ำกัน (ซึ่งฉันเคยพบมานานแล้วเมื่อฉันเพิ่งเริ่มต้นด้วย " $ PATH = $ PATH: / new / dir "สิ่งนี้ทำให้แน่ใจว่าฉันได้รับสำเนาที่สะอาดตามลำดับที่ฉันต้องการ


1
แนะนำทางเลือกอื่น: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"มันจะสั้นลงและง่ายขึ้นในการเพิ่ม dir ใหม่ (เพียงแค่คัดลอกบรรทัดแล้วแก้ไขส่วน "d = .... " แรก) อย่างไรก็ตามสำหรับเส้นทางที่หนึ่งฉันคิดว่าคุณจะจบลงด้วยจำนวนมากเกินไปในเส้นทางของคุณซึ่งไม่ดีเสมอไป (ถ้ามีคำสั่ง "foo" อยู่ในเส้นทางที่รู้จักน้อยกว่าและทำสิ่งที่แตกต่างอย่างสิ้นเชิง สิ่งที่ผู้ใช้ทั่วไปจะคาดหวัง?)
Olivier Dulac

OP ขอวิธีสั้น ๆ เพื่อเพิ่มเส้นทาง นี่เป็นสิ่งที่ละเอียดมากและมีแนวโน้มที่จะเกิดข้อผิดพลาดมากกว่าสิ่งที่พวกเขาพยายามหลีกเลี่ยงอยู่แล้ว
underscore_d

-1

มีวิธีง่าย ๆ ! อ่านฟังก์ชั่นเชลล์และตัวแปรพา ธที่Linux Journal , 01 มีนาคม 2000 โดย Stephen Collyer

ฟังก์ชั่นให้ฉันใช้ชนิดข้อมูลใหม่ในสภาพแวดล้อมทุบตีของฉัน - รายการคั่นด้วยโคลอน นอกจาก PATH แล้วฉันยังใช้มันเพื่อปรับ LOCATE_PATH ของฉัน MANPATH และอื่น ๆ และเป็นประเภทข้อมูลทั่วไปในการเขียนโปรแกรมทุบตี นี่คือวิธีที่ฉันตั้งค่าเส้นทางของฉัน (ใช้ฟังก์ชั่น):

# Add my bin directory to $PATH at the beginning, so it overrides 
addpath -f -p PATH $HOME/bin

# For Raspberry Pi development (add at end)
addpath -b -p PATH ${HOME}/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

# remove nonexistent directories from PATH
delpath -n -p PATH

# ensure PATH contains unique entries
uniqpath -p PATH

เนื่องจากลิงก์ของลินุกซ์วารสารเรียกว่า "เสีย" ฉันจึงใส่ฟังก์ชั่น Bash Path ไว้ในไฟล์. shar ที่http://pastebin.ubuntu.com/13299528/


3
ฟังก์ชั่นเหล่านี้คืออะไร? OP ใช้งานอย่างไร สันนิษฐานว่ามันถูกอธิบายไว้ในลิงก์ที่ขาดในคำตอบของคุณซึ่งเป็นเหตุผลที่เราต้องการให้มีคำตอบอยู่เสมอ โปรดแก้ไขและรวมฟังก์ชั่นที่เกิดขึ้นจริงในคำตอบของคุณ
terdon

@terdon: ลิงก์ใช้งานได้สำหรับฉันฉันวางไฟล์. shar ลงใน pastebin ฉันจะไม่โพสต์บรรทัด 1K ที่นี่
waltinator

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