Henüz orada değilse $ PATH dizinini ekleyin


126

Herhangi biri henüz bulunmamışsa $ PATH dizinine eklemek için bash işlevi yazmış olan var mı?

Genelde PATH'a şöyle birşey eklerim

export PATH=/usr/local/mysql/bin:$PATH

PATH'imi .bash_profile içinde oluşturursam, içinde bulunduğum oturum bir oturum açma oturumu olmadığı sürece okunmaz - bu her zaman doğru değildir. PATH'imi .bashrc içinde oluşturursam, her bir alt kabukla çalışır. Böylece bir Terminal penceresi başlatıp ardından ekranı çalıştırıp ardından bir kabuk betiği çalıştırırsam, şunu alıyorum:

$ echo $PATH
/usr/local/mysql/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:....

Ben add_to_path()sadece orada değilse, dizini ekleyen denilen bir bash işlevi oluşturmaya çalışacağım . Ancak, eğer birileri zaten böyle bir şey yazmışsa (veya bulmuşsa), bunun üzerine zaman harcamam.


Yardımcı olabilecek bazı altyapı için bkz. Stackoverflow.com/questions/273909/… .
dmckee


Sorunu "sadece orada değilse ekleyerek" olarak çerçevelerseniz, eklenen öğenin başında olmasının önemli olduğu, ancak ortaya çıkmadığı gün geldiğinde kabaca şaşıracaksınız. Daha iyi bir yaklaşım, elemanın yerleştirilmesi ve kopyaların çıkarılması olacaktır, böylece yeni giriş zaten oradaysa, etkin bir şekilde başlangıcına taşınacaktır.
Don Hatch

Yanıtlar:


125

Benim .bashrc'den:

pathadd() {
    if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
        PATH="${PATH:+"$PATH:"}$1"
    fi
}

PATH zaten dışa aktarılmış olarak işaretlenmiş olmalıdır, bu nedenle yeniden ihracat gerekmez. Bu, dizinin var olup olmadığını denetler ve eklemeden önce bir dizin olup olmadığını umursamadığınız bir dizindir.

Ayrıca, bu yeni dizini yolun sonuna ekler; Başlangıçta PATH="$1${PATH:+":$PATH"}"yukarıdaki PATH=satır yerine kullanın .


26
Umurumda.
Dennis Williamson

4
@Neil: İşe yarıyor, çünkü ":$PATH:"sadece bununla karşılaştırıyor"$PATH"
Gordon Davisson

3
@ GordonDavisson: Özür dilerim, testim yanlış ve sen haklısın.
Neil

2
@ GordonDavisson Kıvrımlı parantez içindeki şeylerin anlamı nedir. Ben " ${PATH:+"$PATH:"}1 $ " bulmaca gibi görünmüyor
boatcoder 21:13 de

5
@ Mark0978: Sorun giderici düzeltmek için bunu yaptım. tanımlanmış ve boş olmayan bir değere sahip ${variable:+value}olup olmadığını variableve değerlendirmenin sonucunu verip vermediğini kontrol etmek anlamına gelir value. Temel olarak, eğer onunla başlamak için PATH boş değilse, onu "$PATH:$1"; Boşsa, sadece onu ayarlar "$1"(iki nokta üst üste olmadığına dikkat edin).
Gordon Davisson

19

Gordon Davisson'ın cevabını genişleterek, bu çoklu argümanları destekliyor

pathappend() {
  for ARG in "$@"
  do
    if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
        PATH="${PATH:+"$PATH:"}$ARG"
    fi
  done
}

Böylece, path1 path2 path3'ü pathappend yapabilirsiniz ...

Hazırlamak için

pathprepend() {
  for ((i=$#; i>0; i--)); 
  do
    ARG=${!i}
    if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
        PATH="$ARG${PATH:+":$PATH"}"
    fi
  done
}

Pathappend'e benzer şekilde yapabilirsiniz

pathprepend yol1 yol2 yol3 ...


3
Bu harika! Küçük bir değişiklik yaptım. 'Pathprepend' fonksiyonu için, argümanları tersten okumanız uygundur, böylece örneğin diyebilir pathprepend P1 P2 P3ve bitebilirsiniz PATH=P1:P2:P3. Bu davranışı elde etmek için, değiştirmek for ARG in "$@" doiçinfor ((i=$#; i>0; i--)); do ARG=${!i}
ishmael

Teşekkürler @ishmael, iyi öneri, cevabı değiştirdim. Yorumunuzun iki yıldan daha eski olduğunu biliyorum, ancak o zamandan beri geri dönmedim. Borsa e-postalarını gelen kutuma nasıl aktaracağımı bulmak zorundayım!
Guillaume Perrault-Archambault,

14

İşte gelen şey benim cevap için bu soruya Doug Harris fonksiyonunun yapısı ile birleştirdi. Bash düzenli ifadelerini kullanır:

add_to_path ()
{
    if [[ "$PATH" =~ (^|:)"${1}"(:|$) ]]
    then
        return 0
    fi
    export PATH=${1}:$PATH
}

Bu benim için sadece $1yerine kullanarak çalıştı${1}
Andrei

@Andrei: Evet, bu durumda diş telleri gereksizdir. Onları neden dahil ettiğimden emin değilim.
Dennis Williamson,

10

Bunu seçilen cevaba yapılan yorumlara ekleyin, ancak yorumlar PRE formatını desteklemiyor gibi görünüyor, bu nedenle cevabı buraya ekleyin:

@ gordon-davisson Ben gereksiz alıntı ve birleştirme büyük bir hayranı değilim. Bir bash sürümü> = 3 kullandığınızı varsayarsak, bunun yerine bash'in yerleşik regex'lerinde kullanabilir ve şunu yapabilirsiniz:

pathadd() {
    if [ -d "$1" ] && [[ ! $PATH =~ (^|:)$1(:|$) ]]; then
        PATH+=:$1
    fi
}

Bu, dizinde veya PATH'ta boşlukların olduğu durumları doğru şekilde işler. Bash'ın regex motorunda yerleşik olarak bulunmasının yeterince yavaş olup olmadığına dair bazı sorular var.


1
Yorumlar formatting using the backtickyalnızca desteklemektedir ancak düzgün bir paragraf kontrolü alamazsınız.
kayıkçı

Bu, ekleme işlemini en sonda yerine getirir. Mevcut konumları geçersiz kılmak için başlangıcına ekleme yapmak genellikle istenir.
Dennis Williamson,

@DennisWilliamson Bu adil bir nokta, ancak bunu varsayılan davranış olarak önermem. Bir hazırlık için nasıl değiştirileceğini bulmak zor değil.
Christopher Smith

@ChristopherSmith - re: boş olmayan, unnecessary quotingvaktinden önce bildiğinizi belirtir $PATH. "$PATH"PATH'in null olup olmadığını OK yapar. Benzer şekilde $1, komut ayrıştırıcısını şaşırtacak karakterler içeriyorsa. Regex'i tırnak içine almak bunu "(^|:)$1(:|$)"önler.
Jesse Chisholm

@JesseChisholm: Aslında, Christopher’ın amacının kuralların [[ve arasında farklı olduğunu düşünüyorum ]]. Bunu bozulmasına neden olmaktadır sürece muhtemelen, alıntılanan gereken her şeyi alıntı yapmak tercih ederim ama o haklı inanıyoruz ve bu değildir gerçekten tırnak ihtiyaç etrafında $PATH. Öte yandan, haklı olduğun anlaşılıyor $1.
Scott,

7
idempotent_path_prepend ()
{
    PATH=${PATH//":$1"/} #delete any instances in the middle or at the end
    PATH=${PATH//"$1:"/} #delete any instances at the beginning
    export PATH="$1:$PATH" #prepend to beginning
}

$ PATH'nizin başında tam olarak bir kez görünmesi için $ HOME / bin uygulamasına ihtiyaç duyduğunuzda ve başka hiçbir yerde olmadığınızda, başka hiçbir şey kabul etmeyin.


Teşekkürler, bu güzel ve zarif bir çözüm, fakat işe yaraması için PATH=${PATH/"... yerine ... yapmam gerektiğini buldum PATH=${PATH//".
Mark Booth,

Çift eğik çizgi formu herhangi bir sayıda eşleşmeyle eşleşmelidir; tek eğik çizgi yalnızca birinciyle eşleşir (bash man sayfasında "Desen değiştirme" ifadesini arayın). Neden işe yaramadı bilmiyorum ...
andybuckley 27:13

Bu $1, tek giriş olan olağandışı durumda başarısız olur (sütun yok). Giriş iki katına çıkar.
Dennis Williamson,

Ayrıca PeterS6g tarafından belirtildiği gibi çok agresif bir şekilde siler .
Dennis Williamson

6

İşte gereksiz girişlerden kurtulmanın ek avantajına sahip alternatif bir çözüm:

function pathadd {
    PATH=:$PATH
    PATH=$1${PATH//:$1/}
}

Bu işlevin tek argümanı PATH'a hazırlanmıştır ve aynı dizgenin ilk örneği varolan yoldan kaldırılmıştır. Başka bir deyişle, dizin yolda zaten mevcutsa, kopya olarak eklemek yerine öne doğru yükseltilir.

İşlev, tüm girişlerin önde bir sütunu olmasını sağlamak için yola bir sütun hazırlayarak ve ardından o girdi kaldırılmış olarak varolan yola yeni giriş hazırlayarak çalışır. Son bölüm bash ${var//pattern/sub}notasyonu kullanılarak gerçekleştirilir ; bkz bash kılavuzu daha fazla ayrıntı için.


Güzel düşünce; kusurlu uygulama. Sizde ve sizde zaten varsa /home/robert, ne olacağını düşünün . PATHpathadd /home/rob
Scott,

5

İşte benim (sanırım yıllar önce eski laboratuarımın sistem yöneticisi Oscar tarafından yazılmış, ona kredi verildi), yıllardır bashrc'imdeydi. Yeni dizini istediğiniz gibi hazırlamanıza veya eklemenize izin vermenin yararı vardır:

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

Kullanımı:

$ echo $PATH
/bin/:/usr/local/bin/:/usr/bin
$ pathmunge /bin/
$ echo $PATH
/bin/:/usr/local/bin/:/usr/bin
$ pathmunge /sbin/ after
$ echo $PATH
/bin/:/usr/local/bin/:/usr/bin:/sbin/

5

Hazırlık yapmak için, Russell'ın çözümünü seviyorum, ancak küçük bir hata var: "/ bin" gibi bir şeyi "/ sbin: / usr / bin: / var / usr / bin: / usr / local yoluna hazırlamaya çalışırsanız / bin: / usr / sbin "bu" / bin: "ifadesini 3 kez değiştirir (gerçekten hiç uyuşmadığında). Bunun için bir düzeltme @ gordon-davisson gelen çözüm ekleyerek, şunu alıyorum:

path_prepend() {
    if [ -d "$1" ]; then
        PATH=${PATH//":$1:"/:} #delete all instances in the middle
        PATH=${PATH/%":$1"/} #delete any instance at the end
        PATH=${PATH/#"$1:"/} #delete any instance at the beginning
        PATH="$1${PATH:+":$PATH"}" #prepend $1 or if $PATH is empty set to $1
    fi
}

4

Aşağıdaki gibi basit bir takma ad hile yapmak gerekir:

alias checkInPath="echo $PATH | tr ':' '\n' | grep -x -c "

Tek yaptığı yolu: karakterindeki yolu bölmek ve her bileşeni girdiğiniz argümanla karşılaştırmaktır. Grep tam bir çizgi eşleşmesi olup olmadığını kontrol eder ve sayısını yazdırır.

Örnek kullanım:

$ checkInPath "/usr/local"
1
$ checkInPath "/usr/local/sbin"
1
$ checkInPath "/usr/local/sbin2"
0
$ checkInPath "/usr/local/" > /dev/null && echo "Yes" || echo "No"
No
$ checkInPath "/usr/local/bin" > /dev/null && echo "Yes" || echo "No"
Yes
$ checkInPath "/usr/local/sbin" > /dev/null && echo "Yes" || echo "No"
Yes
$ checkInPath "/usr/local/sbin2" > /dev/null && echo "Yes" || echo "No"
No

Echo komutunu addToPath veya benzeri bir takma ad / işlev ile değiştirin.


"Grep -x" kullanmak muhtemelen bash fonksiyonuma koyduğum döngüden daha hızlı.
Doug Harris


2

İşte çırptığım şey:

add_to_path ()
{
    path_list=`echo $PATH | tr ':' ' '`
    new_dir=$1
    for d in $path_list
    do
        if [ $d == $new_dir ]
        then
            return 0
        fi
    done
    export PATH=$new_dir:$PATH
}

Şimdi .bashrc içinde var:

add_to_path /usr/local/mysql/bin

Orijinalimin boşluk içeren dizinleri nasıl işleyemeyeceği hakkındaki yorumdan sonra güncellenmiş sürüm ( beni kullanmaya yönlendirdiğim için bu soru sayesinde IFS):

add_to_path ()
{
    new_dir=$1
    local IFS=:
    for d in $PATH
    do
        if [[ "$d" == "$new_dir" ]]
        then
            return 0
        fi
    done
    export PATH=$new_dir:$PATH
}

1
Herhangi bir dizin adı zaten içinde bu başarısız olabilir PATHboşluk içeriyor, *, ?veya [... ].
Scott,

İyi nokta ... ama ben eski okul bir linux adamım ve içinde beyaz boşluk olan bir yolu asla kullanmazdım :-)
Doug Harris

Adlarına boşluk bırakan şeyler yaratmadığın için sana iyi gelir. Var olduklarında bunlarla başa çıkamayan kod yazmanız için size utanç verin. Ve “eski okul bir Linux adamı” olmanın bununla ne alakası var? Windoze fikri popülerleştirmiş olabilir (teşekkür ederim Documents and Settingsve Program Files), ancak Unix, Windoze'nin varlığından bu yana beyaz boşluk içeren yol adlarını destekledi .
Scott,

2

Henüz kimseden bahsetmediğine biraz şaşırdım, ancak readlink -fgöreceli yolları mutlak yollara dönüştürmek ve bunları PATH'a eklemek için kullanabilirsiniz.

Örneğin, Guillaume Perrault-Archambault'un cevabını geliştirmek için,

pathappend() {
  for ARG in "$@"
  do
    if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
        PATH="${PATH:+"$PATH:"}$ARG"
    fi
  done
}

olur

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. Temel Bilgiler - Bu Ne İşe Yarar?

readlink -fKomutu (diğer şeyler arasında) mutlak bir yol göreli bir yol dönüştürecektir. Bu gibi bir şey yapmanıza olanak sağlar

$ cd / yol / to / my / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / yol / to / my / bin / dir

2. Niçin PATH Twice İçinde Test Yapıyoruz?

Peki, yukarıdaki örneği düşünün. Kullanıcı diyorsa gelen ikinci kez dizine, olacaktır . Tabii ki, içinde olmayacak . Ama sonra ayarlanır (mutlak yol eşdeğeri ), olduğu zaten . Bu yüzden eklemekten kaçının ihtiyaç için ikinci kez.pathappend ./path/to/my/bin/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH

Belki daha da önemlisi, asıl amacı readlink, adından da anlaşılacağı gibi, sembolik bir bağlantıya bakmak ve içerdiği yol adını okumaktır (yani işaret eder). Örneğin:

$ 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

Şimdi, eğer söylerseniz pathappend /usr/lib/perl/5.14ve /usr/lib/perl/5.14PATH'inizde zaten varsa , peki, sorun değil; sadece olduğu gibi bırakabiliriz. Ama, eğer /usr/lib/perl/5.14PATH içinde zaten değil, biz diyoruz readlinkve almak ARGA= /usr/lib/perl/5.14.2, ve sonra biz eklemek o kadar PATH. Ama bir dakika - eğer zaten söyledi pathappend /usr/lib/perl/5.14, o zaman zaten /usr/lib/perl/5.14.2yine biz eklemeden önlemek için için kontrol edilmesi gereken PATH içinde ve PATHikinci kez.

3. Ne ile başa çıkmak if ARGA=$(readlink -f "$ARG")?

Belirsiz olması durumunda, bu çizgi readlinkbaşarılı olup olmadığını test eder . Bu sadece iyi, savunma amaçlı programlama uygulamasıdır. Eğer m komutunun çıkışını n komutunun bir  parçası olarak kullanacaksak  (burada m  <  n ), m komutunun başarısız olup olmadığını kontrol etmek ve bunu bir şekilde ele almak akıllıca olacaktır  . Bunun başarısız olacağını düşünmüyorum - ancak, OS X'den ve başka bir yerden keyfi bir dosyanın mutlak yolunun nasıl alınacağı , bir GNU icadıdır. POSIX’de belirtilmediğinden, Mac OS, Solaris ve diğer Linux olmayan Unix’lerde kullanılabilirliği sorgulanabilir. (Aslında, ben sadece şöyle yazan bir yorum okudum :readlinkreadlinkreadlink -fMac OS X 10.11.6'da çalışmıyor gibi görünüyor, ancak realpathkutudan çıkıyor. ”Yani, sizde olmayan readlinkveya readlink -fçalışmayan bir sistemde iseniz , bunu değiştirebileceksiniz. kullanılacak komut dosyası realpath.) Bir güvenlik ağı kurarak kodumuzu biraz daha taşınabilir hale getiririz.

Tabii ki, readlink(veya  realpath) olmayan bir sistemdeyseniz, yapmak istemeyeceksiniz .pathappend .

İkinci -dtest ( [ -d "$ARGA" ]) gerçekten gereksizdir. $ARGBir dizin ve readlinkbaşarılı olan herhangi bir senaryo düşünemiyorum , ancak  $ARGAbir dizin değil. ifÜçüncü ifadeyi oluşturmak için ilk ifadeyi kopyalayıp yapıştırdım ve -dtesti orada tembelliğin dışında bıraktım  .

4. Başka Yorumlarınız var mı?

Evet. Buradaki diğer cevapların birçoğu gibi, bu da her bir argümanın bir dizin olup olmadığını test eder, öyleyse onu işler ve değilse, onu yok sayar. Bu pathappend sadece (“ ve .benzeri ) dosyalarda ve diğer komut dosyalarında kullanıyorsanız (veya olmayabilir) yeterli olabilir . Ancak, bu cevabın (yukarıda) gösterdiği gibi, etkileşimli olarak kullanmak tamamen mümkün. Eğer yaparsan çok şaşırırsın.bash_profile.bashrc

$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found

Dediğim fark ettin nysql içinde pathappendyerine, komuta mysql? Ve bu pathappendhiçbir şey söylemedi; sadece sessizce yanlış argümanı görmezden geldi?

Yukarıda söylediğim gibi, hatalarla baş etmek iyi bir uygulamadır. İşte bir örnek:

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
}

(1) tırnak eklemek gerekir: readlink -f "$ARG". (2) Bunun neden olacağını bilmiyorum (özellikle -d "$ARG"test başarılı olduktan sonra ), ancak readlinkbaşarısız olup olmadığını test etmek isteyebilirsiniz . (3) readlinkBirincil işlevi görmüyorsunuz - sembolik bir link ismini “gerçek bir dosya ismiyle” eşlemek için. Eğer (örneğin) /binsembolik bir link ise /bin64, tekrarlanan çağrılar pathappend /binPATH deyişi ile sonuçlanabilir …:/bin64:/bin64:/bin64:/bin64:…. Büyük olasılıkla (ayrıca) yeni değerinin $ARGzaten var olup olmadığını kontrol etmelisiniz PATH.
Scott,

(1) İyi gözlem, düzelttim. (2) hangi durumda readlink başarısız olur? Bir yolun doğru olduğunu ve geçerli bir yeri ifade ettiğini varsayarsak. (3) Okuma bağlantısının birincil işlevini neyin belirlediğinden emin değilim, bir unix dosya sistemindeki yolların çoğunun (tümü değil mi?) İki tür bağlantıya, sembolik bağlantılara ve sabit bağlantılara bölünebileceğine inanıyorum. Yinelenen yol girişine gelince haklısınız, ancak cevabımın amacı bunu eklemek değildi (diğer cevapların daha önce bahsettiğini fark ettiğim gibi). Başka bir cevap eklememin tek nedeni, henüz katkıda bulunmadığını düşündüğüm bir şeye katkıda bulunmak
qwertyzw

(2) Demek istediğim, en azından komutun adı, amacına ima edilmiş / ima edilmişse, okuma linkindeki 'link', sert veya yumuşak linklere atıfta bulunabilir. Ancak haklısın: man readlink 'readlink - yazdırılan çözülmüş sembolik bağları veya kanonik dosya adlarını' diyor, örneğimde .kanonik bir dosya adı olarak kabul edilebileceğini düşünüyorum. Doğru?
qwertyzw

(1) Sembolik bağları anlayan insanlara, readlinkadı açıkça amacına işaret eder - sembolik bir bağa bakar ve içerdiği yol adını okur (yani işaret eder). (2) Neden başarısız olacağını bilmiyordum dedimreadlink . Eğer bir komut dosyası veya işlev birden fazla komut içeriyorsa ve n komutunun  felaketle başarısız olacağını garanti edersem (ya da hiç mantıklı değil), m komutunun başarısız olması durumunda  (burada m  <  n ), ihtiyatlı iyi bir uygulama olduğunu genel olarak belirttim. m komutunun başarısız olup olmadığını kontrol edin ve bunu bir şekilde ele alın - en azından,… (Devam)
Scott

(Devam))… komut dosyası / işlevi bir tanılama ile iptal edin. Varsayımsal olarak, readlink(a) dizininizin adı değiştirilmişse veya silinmişse (başka bir işlemle) testve readlink/ veya (b) /usr/bin/readlinksilinmişse (veya bozulmuşsa) başarısız olabilir . (3) Benim amacımı kaçırıyor gibisin. Diğer cevapları cevaplamanızı tavsiye etmiyorum; Orijinalin ARG(komut satırından) zaten içeride olup olmadığını kontrol ederek PATH, ancak yeninin (çıktının ) kontrolünü tekrar etmeden, cevabınızın eksik ve bu nedenle yanlış olduğunu söylüyorum . … (Devam ediyor)ARGreadlink
Scott

1
function __path_add(){  
if [ -d "$1" ] ; then  
    local D=":${PATH}:";   
    [ "${D/:$1:/:}" == "$D" ] && PATH="$PATH:$1";  
    PATH="${PATH/#:/}";  
    export PATH="${PATH/%:/}";  
fi  
}  

1

Bu yol iyi çalışıyor:

if [[ ":$PATH:" != *":/new-directory:"* ]]; then PATH=${PATH}:/new-directory; fi

0

Sürümlerim boş yollar konusunda daha az dikkatli ve geçerli olan yollarda ve dizinlerin burada yayınlananlardan daha az dikkatli olmasına dikkat ediyor, ancak ben prepend / append / clean / unique-ify / etc gibi geniş bir ish koleksiyonu buluyorum. kabuk fonksiyonları, yol manipülasyonu için faydalı olacaktır. Bugünkü haliyle, her şey burada: http://pastebin.com/xS9sgQsX (geri bildirim ve iyileştirmeler çok hoş geldiniz!)


0

Perl one liner kullanabilirsiniz:

appendPaths() { # append a group of paths together, leaving out redundancies
    # use as: export PATH="$(appendPaths "$PATH" "dir1" "dir2")
    # start at the end:
    #  - join all arguments with :,
    #  - split the result on :,
    #  - pick out non-empty elements which haven't been seen and which are directories,
    #  - join with :,
    #  - print
    perl -le 'print join ":", grep /\w/ && !$seen{$_}++ && -d $_, split ":", join ":", @ARGV;' "$@"
}

İşte bash içinde:

addToPath() { 
    # inspired by Gordon Davisson, http://superuser.com/a/39995/208059
    # call as: addToPath dir1 dir2
    while (( "$#" > 0 )); do
    echo "Adding $1 to PATH."
    if [[ ! -d "$1" ]]; then
        echo "$1 is not a directory.";
    elif [[ ":$PATH:" == *":$1:"* ]]; then
        echo "$1 is already in the path."
    else
            export PATH="${PATH:+"$PATH:"}$1" # ${x:-defaultIfEmpty} ${x:+valueIfNotEmpty}
    fi
    shift
    done
}

0

Hiçbiri sağlanmamışsa, geçerli dizini kullanmak için Gordon Davisson'ın cevabını biraz değiştirdim . Böylece paddPATH'inize eklemek istediğiniz dizinden sadece yapabilirsiniz .

padd() {
  current=`pwd`
  p=${1:-$current}
  if [ -d "$p" ] && [[ ":$PATH:" != *":$p:"* ]]; then
      PATH="$p:$PATH"
  fi
}

0

Özel bir değişkenin ayarlanıp ayarlanmadığını kontrol edebilirsiniz, aksi takdirde ayarlayın ve ardından yeni girişleri ekleyin:

if [ "$MYPATHS" != "true" ]; then
    export MYPATHS="true"
    export PATH="$PATH:$HOME/bin:"

    # java stuff
    export JAVA_HOME="$(/usr/libexec/java_home)"
    export M2_HOME="$HOME/Applications/apache-maven-3.3.9"
    export PATH="$JAVA_HOME/bin:$M2_HOME/bin:$PATH"

    # etc...
fi

Tabii ki, bu girişler, gibi başka bir komut dosyası tarafından eklenirse yine çoğaltılabilir /etc/profile.


0

Bu komut dosyası sonunda eklemenizi sağlar $PATH:

PATH=path2; add_to_PATH after path1 path2:path3
echo $PATH
path2:path1:path3

Veya başında ekleyin $PATH:

PATH=path2; add_to_PATH before path1 path2:path3
echo $PATH
path1:path3:path2

# Add directories to $PATH iff they're not already there
# Append directories to $PATH by default
# Based on https://unix.stackexchange.com/a/4973/143394
# and https://unix.stackexchange.com/a/217629/143394
add_to_PATH () {
  local prepend  # Prepend to path if set
  local prefix   # Temporary prepended path
  local IFS      # Avoid restoring for added laziness

  case $1 in
    after)  shift;; # Default is to append
    before) prepend=true; shift;;
  esac

  for arg; do
    IFS=: # Split argument by path separator
    for dir in $arg; do
      # Canonicalise symbolic links
      dir=$({ cd -- "$dir" && { pwd -P || pwd; } } 2>/dev/null)
      if [ -z "$dir" ]; then continue; fi  # Skip non-existent directory
      case ":$PATH:" in
        *":$dir:"*) :;; # skip - already present
        *) if [ "$prepend" ]; then
           # ${prefix:+$prefix:} will expand to "" if $prefix is empty to avoid
           # starting with a ":".  Expansion is "$prefix:" if non-empty.
            prefix=${prefix+$prefix:}$dir
          else
            PATH=$PATH:$dir  # Append by default
          fi;;
      esac
    done
  done
  [ "$prepend" ] && PATH=$prefix:$PATH
}

0

İşte POSIX uyumlu bir yol.

# USAGE: path_add [include|prepend|append] "dir1" "dir2" ...
#   prepend: add/move to beginning
#   append:  add/move to end
#   include: add to end of PATH if not already included [default]
#          that is, don't change position if already in PATH
# RETURNS:
# prepend:  dir2:dir1:OLD_PATH
# append:   OLD_PATH:dir1:dir2
# If called with no paramters, returns PATH with duplicate directories removed
path_add() {
    # use subshell to create "local" variables
    PATH="$(path_unique)"
    export PATH="$(path_add_do "$@")"
}

path_add_do() {
    case "$1" in
    'include'|'prepend'|'append') action="$1"; shift ;;
    *)                            action='include'   ;;
    esac

    path=":$PATH:" # pad to ensure full path is matched later

    for dir in "$@"; do
        #       [ -d "$dir" ] || continue # skip non-directory params

        left="${path%:$dir:*}" # remove last occurrence to end

        if [ "$path" = "$left" ]; then
            # PATH doesn't contain $dir
            [ "$action" = 'include' ] && action='append'
            right=''
        else
            right=":${path#$left:$dir:}" # remove start to last occurrence
        fi

        # construct path with $dir added
        case "$action" in
            'prepend') path=":$dir$left$right" ;;
            'append')  path="$left$right$dir:" ;;
        esac
    done

    # strip ':' pads
    path="${path#:}"
    path="${path%:}"

    # return
    printf '%s' "$path"
}

# USAGE: path_unique [path]
# path - a colon delimited list. Defaults to $PATH is not specified.
# RETURNS: `path` with duplicated directories removed
path_unique() {
    in_path=${1:-$PATH}
    path=':'

    # Wrap the while loop in '{}' to be able to access the updated `path variable
    # as the `while` loop is run in a subshell due to the piping to it.
    # https://stackoverflow.com/questions/4667509/shell-variables-set-inside-while-loop-not-visible-outside-of-it
    printf '%s\n' "$in_path" \
    | /bin/tr -s ':' '\n'    \
    | {
            while read -r dir; do
                left="${path%:$dir:*}" # remove last occurrence to end
                if [ "$path" = "$left" ]; then
                    # PATH doesn't contain $dir
                    path="$path$dir:"
                fi
            done
            # strip ':' pads
            path="${path#:}"
            path="${path%:}"
            # return
            printf '%s\n' "$path"
        }
}

Bu cribbed edilir Guillaume Perrault-Archambault 'ın cevabı bu soruya ve mike511 ' ın cevabı burada .

GÜNCELLEME 2017-11-23: @Scott başına sabit hata


Varsayılan olarak, hazırlama ve gönderme (ekleme) arasında seçim yapmak için bir komut satırı seçeneği sağlamak için bunu oylayacağım. Ama sonra düşündüm: Bu açıklama olmadan bir sürü şifreli kod çoktur. (Ve bir PATH değiştirir ve yeni bir değer yankıları ve diğer nereye, iki işlevi vardır aslında o çıkışını yakalayan ve yine PATH atar , sadece gereksiz bir karmaşıklık budur.) ... (devamı)
Scott

(Devam ediyor)… Ve sonra bağlantıların yanlış olduğunu fark ettim. (Ve neden bu adamları suçladığınızdan emin değilim; onların cevaplarından çok fazla şey kopyalamış görünmüyorsunuz.) Ve sonra kodun yanlış olduğunu fark ettim . İyi biçimlendirilmiş bir PATH'yi sürdürmek için iyi bir iş çıkardığını düşünüyorum , ama özellikle de aydınlatılmamış bir durumda olduğunuzda, zaten iyi biçimlendirilmiş olduğuna dair hiçbir garanti yok /etc/profile. PATH’a eklemeye çalıştığınız dizin zaten bir kereden fazla orada olabilir ve kodunuz boğulur. … (Devam ediyor)
Scott

Eğer başa eklemek denerseniz (devamı) ... Örneğin, /a/ckiçin /b:/a/ck:/tr:/a/ckelde edersiniz /a/ck:/b:/a/ck:/tr:/tr:/a/ck.
Scott
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.