Uzun bir $ PATH düzenlemenin daha konforlu bir yolu?


35

~ / .Bashrc dizininde $ PATH dizinine birkaç dizin eklemek istiyorum.

$ PATH'im oldukça uzun, bu yüzden hangi dizinleri ve hangi sıraları içerdiğini görmek biraz zor.

~ / .Bashrc kodumu değiştirebileceğimi biliyorum:

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

okumayı kolaylaştıracaktı. Ancak son yıllarda Bash'in uzun bir PATH belirlemeyi kolaylaştıran bazı sözdizimi alıp almadığını merak ediyordum. Örneğin, şuna benzer bir sözdizimi hayal ediyorum:

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

Böyle bir sözdiziminin geçersiz olduğunu biliyorum . Bu kadar kolay bir şey olup olmadığını merak ediyordum. Var mı?


Geleneksel öğretici aracılığıyla yolunu ayarlamak için PATH=foo:$PATHbu büyüme her zaman tutmak çünkü yanlış görünüyor source ~/.bashrcve hatta exec bashyardım beri olamaz $PATHolduğu export.
5: 44'te

Yanıtlar:


25

Bir değişkene yol hazırlamak veya eklemek için bir takım işlevler kullanıyorum. İşlevler, Bash için dağıtım dizininde "pathfuncs" adlı bir katkı dosyasında gelir.

  • add_path, girişi PATH değişkeninin sonuna ekler
  • pre_path girdiyi PATH değişkeninin başına ekler
  • del_path, girişi olduğu yerde PATH değişkeninden kaldıracak

İkinci değişken olarak bir değişken belirtirseniz, PATH yerine onu kullanır.

Kolaylık sağlamak için işte bunlar:

# 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;:\$;;"`
}

Bunları bash başlangıç ​​dosyanıza eklerseniz, PATH'inize şöyle ekleyebilirsiniz:

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

Veya farklı bir değişken belirtin:

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

Bu dosyayı, pre_paths'ı ve add_pathssini ikinci koyarak rc dosyalarımda kullanırım. Bu, tüm yol değişikliklerimin bir bakışta anlaşılmasını kolaylaştırıyor. Diğer bir yararı, satırların yeterince kısa olması ve hatta gerekirse bir satıra bir yorum ekleyebileceğim.

Bunlar işlev olduklarından, komut satırından etkileşimli olarak kullanabilirsiniz, örneğin add_path $(pwd)geçerli dizini yola eklemek gibi .


Teşekkürler. Kodunu kontrol ettim ve işe yarıyor. Şaşırtıcı bir şekilde, del_path için de bir kullanım buldum (A "." Bazı durumlarda PATH'uma sürünüyor, şeytan nereden biliyor, ben de yaptım del_path .).
Niccolo M.

Merhaba. Bu pathfunc'ları bashrc betiğinden kaynaklamak (dahil etmek) mümkün mü yoksa bunları kopyalayıp yapıştırmalı mıyım?
Cristiano

@Cristiano Ya çalışacak. Gerçekten sana kalmış.
Denizyıldızı

11

Tamam, sanırım zarif olduğunu düşündüğüm şu çözümü buldum (kabuğun sözdizimine kadar). Bash'in dizi sözdizimini ve öğelere katılmak için temiz bir yol kullanır:

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

ALARM!

Bu çözümün bir sorunu olduğu ortaya çıktı : @terdon ve @ Starfish çözümlerinin aksine, önce yolların zaten PATH'de olup olmadığını kontrol etmiyor. Bu yüzden, bu kodu ~ / .bashrc dizinine koymak istediğimden (ve ~ / .profile dizininde değil), yinelenen yollar PATH içine sürünecek. Bu yüzden bu çözümü kullanmayın (eğer Bash'e özgü bir sözdizimine sahip ~ / .profile (veya daha iyi, ~ / .bash_profile) koymadığınız sürece).


1
Çok hoş. Lütfen bir cevap kabul edebilir misiniz, başkaları daha önce bulduğunuzda bir çözüm önermek için buraya gelmez mi? Teşekkürler
Temel

Yinelenen yollar gerçekten bir sorun değil. PATHPerformans sorunlarına neden olmak için yeterli sayıda dizin eklemeniz pek olası değildir (özellikle de kabuk başarılı aramaları önbelleğe aldığından beri).
chepner

5

Aşağıdaki işlevi benim içerisinde kullanıyorum ~/.bashrc. Eski laboratuarımdaki bir sysadmin'den aldığım bir şey ama onları yazdığını sanmıyorum. Sadece bu satırları eklemek ~/.profileveya ~/.bashrc:

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

Bunun çeşitli avantajları vardır:

  • Yeni dizinler eklemek $PATHönemsizdir pathmunge /foo/bar:;
  • Kopyalanan girişleri önler;
  • Yeni bir girişin başlangıcına mı ( pathmunge /foo/baryoksa sonuna) (sonuna pathmunge /foo/bar) eklenip eklenmeyeceğini seçebilirsiniz $PATH.

Kabuğunuzun başlatma dosyası daha sonra şöyle bir şey içerecektir:

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

Teşekkürler. Ama @ Starfish'in çözümünü seçeceğim çünkü onun ortaya çıkışı yok grep.
Niccolo M.

2
@NiccoloM. Hiç sorun değil, hangisini tercih edeceğinizi kabul edin. Yine de denizyıldızının yaklaşımına dikkat edin eval, yanlış bir argümanla çalıştırırsanız ciddi bir hasara neden olabilmeniz için keyfi kodlar uygular.
terdon

Harici komut olmadan bunu yapmak için daha hızlı fonksiyon bulunduğunu unutmayın grep, bkz. Bugzilla.redhat.com/show_bug.cgi?id=544652#c7
皞 皞

4

~ / .Bashrc dizininde $ PATH dizinine birkaç dizin eklemek istiyorum.

Aşağıdakileri Cygwin'de kullanıyorum. Bash'ın diğer sürümlerinde çalışması gerekir. Akımınızı unset PATHoluşturmak için PATHişareti kaldırabilirsiniz (bunu yaparsanız, :ayırıcıların doğru şekilde nasıl ekleneceğini bulmak zorunda kalabilirsiniz ).

Not:

  • Bir zamanlar bir bashişlevde bu işlevselliğe sahiptim fakat disk çökmesinden sonra onu kaybettim.

Benim içinde .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}"

İçinde ~/.path_elements:

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

Teşekkürler. Cevabınız aklı başında bir çözüm üzerinde çalışmak için beni ilham verdi. (Yolları ayrı bir dosyada saklamak benim zevkime göre can sıkıcı.)
Niccolo M.

1

Bunu .bashrc (ve ayrıca .zshrc'mde kullanıyorum, çünkü genelde bash yerine zsh kullanıyorum). Kabul edilirse, el ile dizinler eklememi gerektiriyor, ancak bunun bir avantajı, güncellediğimde, yeni sunuculara kopyalamaya devam edebileceğimi ve orada bulunmayan dizinlerle oluşturulan yeni bir sunucudaki PATH için endişelenmediğimdir.

##
## PATH
##
## PATH'ımızı sadece dizini ekleyebilecek dizinlerle gizlemek yerine
## bu sunucu için uygun değil, eklediklerimiz hakkında akıllı olmaya çalış
##
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 / yerel / ssl / bin] && PATH = $ PATH: / usr / yerel / 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 / yerel / apache / bin] && PATH = $ PATH: / usr / yerel / 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] && YOL = $ PATH: / usr / xpg4 / bin
[-d / usr / dt / bin] && PATH = $ PATH: / usr / dt / bin

MANPATH için de aynı şeyi yapıyorum:

##
## MANPATH
##
## Yalnızca MANPATH’imizi olabilecek dizinlerle gizlemek yerine
## bu sunucu için uygun değil, eklediklerimiz hakkında akıllı olmaya çalış
##
MANPATH = / usr / local / man
[-d / usr / paylaşım / adam] && MANPATH = $ MANPATH: / usr / paylaşım / adam
[-d / usr / yerel / paylaşım / adam] && MANPATH = $ MANPATH: / usr / yerel / paylaşım / adam
[-d / usr / man] && MANPATH = $ MANPATH: / usr / adam
[-d / cs / erkek] && MANPATH = $ MANPATH: / cs / erkek
[-d / usr / krb5 / erkek] && MANPATH = $ MANPATH: / usr / krb5 / erkek
[-d / usr / kerberos / erkek] && MANPATH = $ MANPATH: / usr / kerberos / erkek
[-d / usr / yerel / ssl / erkek] && MANPATH = $ MANPATH: / usr / yerel / ssl / erkek
[-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 / erkek] && MANPATH = $ MANPATH: / usr / X11R6 / erkek
[-d / usr / yerel / apache / adam] && MANPATH = $ MANPATH: / usr / yerel / apache / adam
[-d / usr / yerel / mysql / man] && MANPATH = $ MANPATH: / usr / yerel / mysql / man
[-d /cs/local/perl5.8.0/man] && MANPATH = $ MANPATH: /cs/local/perl5.8.0/man
[-d / usr / perl5 / erkek] && MANPATH = $ MANPATH: / usr / perl5 / erkek
[-d / usr / yerel / perl / erkek] && MANPATH = $ MANPATH: / usr / yerel / perl / erkek
[-d / usr/local/perl5.8.0/man] && MANPATH = $ MANPATH: /usr/local/perl5.8.0/man
[-d / usr / openwin / adam] && MANPATH = $ MANPATH: / usr / openwin / adam

PATH'a olmayan dizinler eklemekten korkmadan farklı ortamlardaki sistemlere kopyalayabildiğim tek bir dosyaya ek olarak, bu yaklaşım aynı zamanda Dizinlerin PATH'de görünmesini istediğim sırayı belirtmeme izin verme avantajına da sahiptir. Her tanımın ilk satırı PATH değişkenini tamamen yeniden tanımladığından, .bashrc'mi güncelleyebilir ve düzenlemeden sonra kabuğumu yinelenen girişler eklemeden güncellemek için kaynaklayabilirim (uzun zaman önce çoktan başladığımda deneyimledim) $ PATH = $ PATH: / new / dir "Bu arzu ettiğim sırada temiz bir kopya almamı sağlıyor.


1
alternatif önermek: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"Yeni bir dir eklemek daha kısa ve kolay olacaktır (sadece bir satırı kopyalayıp ilk "d = ...." bölümünü düzenleyin). Ancak, PATH olanı için, PATH'nizde çok fazla sayıda dirse sahip olacağınızı düşünüyorum, ki bu her zaman iyi değildir (bazı "foo" komutları daha az bilinen yollardan birinde mevcutsa ve tamamen farklı bir şey yaparsa) normal bir kullanıcının bekleyeceği şey nedir?)
Olivier Dulac 16:15

OP, yol eklemek için daha kısa bir yol istedi. Bu, zaten kaçınmaya çalıştıklarından çok daha ayrıntılı ve hataya açıktır.
underscore_d

-1

Kolay bir yol var! Okuma Kabuk İşlevleri ve Yol Değişkenler de Linux Journal , Mar 01, 2000 tarafından Stephen Collyer

İşlevler bash ortamımda yeni bir veri türü kullanmama izin veriyor - iki nokta üst üste ayrılmış liste. PATH’a ek olarak bunları LOCATE_PATH, MANPATH ve diğerlerini ve bash programlamasında genel bir veri türü olarak ayarlamak için kullanıyorum. PATH'imi şu şekilde ayarlıyorum (işlevleri kullanarak):

# 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

Linux Journal bağlantısı "bozuk" olarak adlandırıldığından, Bash Path İşlevlerini http://pastebin.ubuntu.com/13299528/ adresindeki .shar dosyasına koydum.


3
Bunlar hangi fonksiyonlar? OP bunları nasıl kullanıyor? Muhtemelen cevabınızdaki kopuk bağlantıda açıklanmıştır, bu yüzden kesin olarak cevapların daima kendi içinde olmasını istiyoruz. Lütfen cevabınıza gerçek fonksiyonları düzenleyin ve ekleyin.
terdon

@ terdon: link benim için çalışıyor, pastebin üzerine bir .shar dosyası koydum, buraya 1K satır atmıyorum.
vali

Hata! Şimdi de benim için çalışıyor. Ben yorumdan ayrıldığımda değildi. Her neyse, yorumumun özü, cevaplarda dış kaynaklara bağlanmaktan kaçınmaya çalıştığımızdı. Bilgilerin burada güncellenebileceği, düzenlenebileceği ve çürük kurmaya bağışık olduğu yerde olmasını istiyoruz .
terdon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.