मैं सफाई से $ PATH को कैसे जोड़ सकता हूं?


31

मैं $ PATH, सिस्टम-वाइड या किसी व्यक्तिगत उपयोगकर्ता के लिए चीजों को जोड़ने का एक तरीका चाहूंगा, बिना संभावित रूप से एक ही पथ को कई बार जोड़कर।

ऐसा करने का एक कारण यह है कि इसमें परिवर्धन किया जा सकता है .bashrc, जिसके लिए लॉगिन की आवश्यकता नहीं होती है, और सिस्टम पर अधिक उपयोगी होता है जो कि उपयोग (जैसे) lightdm, जो कभी कॉल नहीं करता है .profile

मैं $ PATH से डुप्लिकेट को साफ करने के तरीके से निपटने वाले सवालों से अवगत हूं , लेकिन मैं डुप्लिकेट को निकालना नहीं चाहता । मैं एक रास्ता जोड़ना चाहूंगा, अगर वे पहले से मौजूद नहीं हैं।



गोल्डी, मुझे नहीं पता कि क्यों, लेकिन मैंने आपकी पहली टिप्पणी भी खाली के साथ देखी थी। लेकिन हाँ, नाम उपसर्ग भी काम करते हैं, कोई चिंता नहीं! दूसरे रास्ते को बंद करना भी ठीक है।
सिरो सेंटिल्ली 新疆 i i i 事件 '

ठीक है, जब तक आपको मेरा संदेश मिला। कभी-कभी इस तरह से उलट-पलट करने से थोड़ी अव्यवस्था होती है, मुझे लगता है कि हम देखेंगे कि क्या होता है।
गोल्डीलॉक्स

जवाबों:


35

मान लीजिए कि हम जो नया रास्ता जोड़ना चाहते हैं वह है:

new=/opt/bin

फिर, किसी भी POSIX शेल का उपयोग करके, हम यह देखने के लिए परीक्षण कर सकते हैं कि newक्या पहले से ही रास्ते में है और यदि नहीं है तो इसे जोड़ दें:

case ":${PATH:=$new}:" in
    *:"$new":*)  ;;
    *) PATH="$new:$PATH"  ;;
esac

कोलन के उपयोग पर ध्यान दें। कॉलनों के बिना, हम सोच सकते हैं कि, कहते हैं, new=/binपहले से ही मार्ग में था क्योंकि यह पैटर्न से मेल खाता था /usr/bin। जबकि PATH में सामान्य रूप से कई तत्व होते हैं, PATH में शून्य और एक तत्व के विशेष मामलों को भी संभाला जाता है। PATH के मामले में शुरू में कोई तत्व नहीं है (खाली होने के कारण) इसके उपयोग से नियंत्रित किया जाता है, ${PATH:=$new}जो यह बताता PATHहै $newकि क्या यह खाली है। इस तरह से मापदंडों के लिए डिफ़ॉल्ट मान सेट करना सभी POSIX शेल की एक विशेषता है: POSIX डॉक्स की धारा 2.6.2 देखें ।)

एक कॉल करने योग्य कार्य

सुविधा के लिए, उपरोक्त कोड को एक फ़ंक्शन में रखा जा सकता है। इस फ़ंक्शन को कमांड लाइन पर परिभाषित किया जा सकता है या, इसे स्थायी रूप से उपलब्ध होने के लिए, अपने शेल के इनिशियलाइज़ेशन स्क्रिप्ट में डाला जाए (बश उपयोगकर्ताओं के लिए, जो होगा ~/.bashrc):

pupdate() { case ":${PATH:=$1}:" in *:"$1":*) ;; *) PATH="$1:$PATH" ;; esac; }

वर्तमान पथ में निर्देशिका जोड़ने के लिए इस पथ अद्यतन फ़ंक्शन का उपयोग करने के लिए:

pupdate /new/path

@ उमर ओके। मैंने उसके लिए एक मामला जोड़ा।
जॉन १०२४

1
आप 2 मामले भेदों को बचा सकते हैं - cf. unix.stackexchange.com/a/40973/1131
मैक्सक्लेपजिग

3
यदि PATHखाली है, तो यह एक खाली प्रविष्टि (यानी वर्तमान निर्देशिका) को जोड़ देगा PATH। मुझे लगता है कि आपको एक और मामला चाहिए।
सीबी बेली

2
@CharlesBailey दूसरा नहीं case। बस करो case "${PATH:=$new}"। इसी तरह की कमियों के लिए मेरा अपना जवाब देखें।
मोकेसर

1
@ mc0e मैंने "लाइन-शोर" को छिपाने के लिए शेल फ़ंक्शन का उपयोग करने का एक उदाहरण जोड़ा।
जॉन १०२४

9

/etc/profile.dनामक फ़ाइल बनाएँ , जैसे, mypath.sh(या जो आप चाहते हैं)। यदि आप lightdm का उपयोग कर रहे हैं, तो सुनिश्चित करें कि यह व्यवहार्य है या फिर /etc/bashrcउसी से उपयोग की गई फ़ाइल या फ़ाइल है। निम्नलिखित कार्यों में जोड़ें:

checkPath () {
        case ":$PATH:" in
                *":$1:"*) return 1
                        ;;
        esac
        return 0;
}

# Prepend to $PATH
prependToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$a:$PATH
                fi
        done
        export PATH
}

# Append to $PATH
appendToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$PATH:$a
                fi
        done
        export PATH
}

$ PATH की शुरुआत (पूर्व निर्धारित) से पहले की चीज़ों का अनुसरण किया जाता है, और इसके विपरीत, अंत में आने वाली चीज़ों (जोड़ा गया) को पहले आने वाली चीज़ों से अलग कर दिया जाएगा। इसका मतलब है कि अगर आपका $ PATH है /usr/local/bin:/usr/binऔर gotchaदोनों निर्देशिकाओं में निष्पादन योग्य है, तो /usr/local/binडिफ़ॉल्ट रूप से उपयोग किया जाएगा।

अब आप - इसी फ़ाइल में, किसी अन्य शेल कॉन्फ़िग फ़ाइल में, या कमांडलाइन से - उपयोग कर सकते हैं:

appendToPath /some/path /another/path
prependToPath /some/path /yet/another/path

यदि यह एक में है .bashrc, तो जब आप एक नया शेल शुरू करते हैं, तो यह मान को एक से अधिक बार प्रदर्शित होने से रोक देगा। इसमें एक सीमा है कि अगर आप उस चीज को जोड़ना चाहते हैं जो पहले से तैयार थी (यानी $ PATH के भीतर एक पथ को स्थानांतरित करें) या इसके विपरीत, आपको इसे स्वयं करना होगा।


के $PATHसाथ विभाजन IFS=:अंततः अधिक लचीला है case
mikeserv

@mikeserv कोई शक नहीं। यह caseIMO के लिए एक तरह का हैक उपयोग है । मुझे लगता है कि awkयहाँ भी अच्छे उपयोग के लिए रखा जा सकता है।
गोल्डीलॉक्स

ये एक अच्छा बिंदु है। और, जैसा कि मुझे लगता है, gawkसीधे असाइन कर सकता है $PATH
मिकसेर्व

5

आप इसे इस तरह से कर सकते हैं:

echo $PATH | grep /my/bin >/dev/null || PATH=$PATH:/my/bin

नोट: यदि आप अन्य चरों से पथ का निर्माण करते हैं, तो जांच लें कि वे खाली नहीं हैं, क्योंकि कई गोले "" जैसे "" की व्याख्या करते हैं। " ।


+1 आदमी पेज के अनुसार -qgrep के लिए POSIX द्वारा आवश्यक है, लेकिन मुझे नहीं पता कि इसका मतलब यह है कि अभी भी कुछ (गैर POSIX) greps हैं जिनके पास यह नहीं है।
गोल्डीलॉक्स

1
ध्यान दें कि grep पैटर्न अत्यधिक विस्तृत है। Egrep -q "(^ |:) / my / bin ((। \ _ $)" का उपयोग करने के बजाय grep / my / bin> / dev / null पर विचार करें। उस संशोधन के साथ आपका समाधान सही है, और मुझे लगता है कि यह @ john1024 से वर्तमान में पसंदीदा उत्तर की तुलना में अधिक पठनीय समाधान है। ध्यान दें कि मैंने दोहरे उद्धरण चिह्नों का उपयोग किया है ताकि आप /my/bin
1616 के

5

कोड का महत्वपूर्ण हिस्सा यह जांचना है कि क्या PATHकोई विशिष्ट पथ है:

printf '%s' ":${PATH}:" | grep -Fq ":${my_path}:"

यही है, सुनिश्चित करें कि विभाजक ( ) द्वारा दोनों तरफ प्रत्येक पथ PATHको सीमांकित किया गया है , फिर जांचें ( क्या) शाब्दिक स्ट्रिंग ( ) में एक विभाजक, आपका पथ और दूसरा विभाजक शामिल है। यदि यह नहीं है तो आप सुरक्षित रूप से पथ जोड़ सकते हैं:PATH:-q-FPATHPATH

if ! printf '%s' ":${PATH-}:" | grep -Fq ":${my_path-}:"
then
    PATH="${PATH-}:${my_path-}"
fi

यह POSIX संगत होना चाहिए, और किसी भी पथ के साथ काम करना चाहिए जिसमें कोई नई रेखा नहीं है। यह अधिक जटिल है यदि आप चाहते हैं कि यह POSIX संगत होने के दौरान नईलाइन वाले रास्तों के साथ काम करे, लेकिन अगर आपके पास कोई ऐसा grepसमर्थन है जो -zआप इसका उपयोग कर सकते हैं।


4

मैं ~/.profileवर्षों से विभिन्न फाइलों में इस छोटे से समारोह को अपने साथ लेकर चल रहा हूं । मुझे लगता है कि यह एक प्रयोगशाला में मैं काम करता था में sysadmin द्वारा लिखा गया था, लेकिन मुझे यकीन नहीं है। वैसे भी, यह गोल्डिलॉक के दृष्टिकोण के समान है लेकिन थोड़ा अलग है:

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

इसलिए, नई निर्देशिका को शुरुआत में जोड़ने के लिए PATH:

pathmunge /new/path

और अंत तक:

pathmunge /new/path after

यह मेरे लिए काम करता है! लेकिन मैंने डिफ़ॉल्ट रूप से इसे डालने के लिए तर्क की अदला-बदली की, और "पहले" के साथ ओवरराइड किया। :)
केविन पाउली

pathmunge linux centos वितरण / etc / प्रोफाइल का हिस्सा है, इसमें पहले और बाद में एक पैरामीटर है। मैं इसे अपने नवीनतम ubuntu 16 में नहीं देखता हूं।
केमिन झोउ

मैकओएस पर ठीक काम करने के लिए लगता है 10.12 के बाद /bin/grep->grep
बेन क्रीसी

4

अद्यतन करें:

मैंने देखा कि आपके स्वयं के उत्तर में अपील करने या करने के लिए प्रत्येक के लिए एक अलग फ़ंक्शन था $PATH। मुझे यह विचार पसंद आया। इसलिए मैंने एक छोटे से तर्क को जोड़ा। मैंने _इसे ठीक से नामांकित भी किया है:

_path_assign() { oFS=$IFS ; IFS=: ; add=$* ; unset P A ; A=
    set -- ${PATH:=$1} ; for p in $add ; do {
        [ -z "${p%-[AP]}" ] && { unset P A
                eval ${p#-}= ; continue ; }
        for d ; do [ -z "${d%"$p"}" ] && break
        done ; } || set -- ${P+$p} $* ${A+$p}
        done ; export PATH="$*" ; IFS=$oFS
}

% PATH=/usr/bin:/usr/yes/bin
% _path_assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/bin/nope \
    -P \
    /usr/nope/bin \
    /usr/bin \
    -A \
    /nope/usr/bin \
    /usr/nope/bin

% echo $PATH

उत्पादन:

/usr/nope/bin:/usr/bin:/usr/yes/bin:/usr/bin/nope:/nope/usr/bin

डिफ़ॉल्ट रूप से यह -Aकरने के लिए ppend होगा $PATH, लेकिन आप अपने तर्कों की सूची में कहीं भी -Pजोड़कर इस व्यवहार को बदलने के लिए बदल सकते हैं -P। आप इसे फिर से -Aसौंपकर वापस ppending पर स्विच कर सकते हैं -A

सेफ ओवल

ज्यादातर मामलों में मैं सलाह देता हूं कि लोग किसी भी तरह के इस्तेमाल से बचें eval। लेकिन यह, मुझे लगता है, अच्छे के लिए इसके उपयोग के एक उदाहरण के रूप में बाहर खड़ा है इस मामले में केवल बयान eval कभी देख सकता है P=या है A=। इसके तर्कों के मूल्यों का कड़ाई से परीक्षण किया जाता है, इससे पहले कि यह कहा जाता है। यह वही eval है जिसके लिए है

assign() { oFS=$IFS ; IFS=: ; add=$* 
    set -- ${PATH:=$1} ; for p in $add ; do { 
        for d ; do [ -z "${d%"$p"}" ] && break 
        done ; } || set -- $* $p ; done
    PATH="$*" ; IFS=$oFS
}

यह उतने ही तर्कों को स्वीकार करेगा जितना आप इसे देते हैं और प्रत्येक को $PATHकेवल एक बार जोड़ते हैं और केवल अगर यह पहले से ही नहीं है $PATH। यह केवल पूरी तरह से पोर्टेबल POSIX शेल-स्क्रिप्ट का उपयोग करता है, केवल शेल-इन-इन्स पर निर्भर करता है, और बहुत तेज़ है।

% PATH=/usr/bin:/usr/yes/bin
% assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/nope/bin \
    /usr/bin \
    /nope/usr/bin \
    /usr/nope/bin

% echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin

@ TAFKA'goldilocks 'अपडेट को यहां देखें - आपने मुझे प्रेरित किया।
मोकेसर

+1 जिज्ञासा से बाहर (शायद यह एक अलग क्यू एंड ए होगा), जहां विचार है कि _उपसर्ग शेल फ़ंक्शन उन्हें "ठीक से नामांकित" बनाते हैं? अन्य भाषाओं में, यह आमतौर पर एक आंतरिक वैश्विक फ़ंक्शन (जो कि वैश्विक होने की आवश्यकता है, लेकिन एक एपीआई के भाग के रूप में बाहरी रूप से उपयोग करने का इरादा नहीं है) को इंगित करेगा। मेरे नाम निश्चित रूप से महान विकल्प नहीं हैं, लेकिन यह मुझे लगता है कि बस का उपयोग _करने से टकराव के मुद्दों को हल नहीं करता है - यह वास्तविक नामस्थान पर निपटने के लिए बेहतर होगा, जैसे।mikeserv_path_assign()
गोल्डीलॉक्स

@ TAFKA'goldilocks '- इसके साथ और भी विशिष्ट प्राप्त करना बेहतर होगा, लेकिन जितना अधिक समय तक नाम कम सुविधाजनक होगा उतना ही इसका उपयोग होता है। लेकिन अगर आपके पास कोई उचित निष्पादन योग्य बायनेरिज़ उपसर्ग है _तो आपको पैकेज प्रबंधकों को स्विच करने की आवश्यकता है। किसी भी मामले में, यह, अनिवार्य रूप से, सिर्फ आ "वैश्विक, आंतरिक, फ़ंक्शन" है - यह शेल से आह्वान किए गए प्रत्येक शेल के लिए वैश्विक है, जिसमें यह घोषित किया गया है, और यह दुभाषिया की स्मृति में व्याख्या की गई भाषा स्क्रिप्ट का केवल एक सा है। । unix.stackexchange.com/questions/120528/...
mikeserv

क्या आप unset aप्रोफ़ाइल के अंत में (या समकक्ष) नहीं कर सकते हैं ?
स्रोतजेडी

0

देखो! औद्योगिक-शक्ति 12-लाइन ... तकनीकी रूप से बैश- और zsh- पोर्टेबल शेल फ़ंक्शन जो आपके पसंद के ~/.bashrcया समर्पित ~/.zshrcस्टार्टअप स्क्रिप्ट को प्यार करता है :

# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
    # For each passed dirname...
    local dirname
    for   dirname; do
        # Strip the trailing directory separator if any from this dirname,
        # reducing this dirname to the canonical form expected by the
        # test for uniqueness performed below.
        dirname="${dirname%/}"

        # If this dirname is either relative, duplicate, or nonextant, then
        # silently ignore this dirname and continue to the next. Note that the
        # extancy test is the least performant test and hence deferred.
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname}:"* &&
           -d "${dirname}" ]] || continue

        # Else, this is an existing absolute unique dirname. In this case,
        # append this dirname to the current ${PATH}.
        PATH="${PATH}:${dirname}"
    done

    # Strip an erroneously leading delimiter from the current ${PATH} if any,
    # a common edge case when the initial ${PATH} is the empty string.
    PATH="${PATH#:}"

    # Export the current ${PATH} to subprocesses. Although system-wide scripts
    # already export the ${PATH} by default on most systems, "Bother free is
    # the way to be."
    export PATH
}

तात्कालिक महिमा के लिए खुद को तैयार करें। फिर, ऐसा करने के बजाय और सबसे अच्छी उम्मीद के लिए:

export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young

इसके बजाय ऐसा करें और सर्वश्रेष्ठ होने की गारंटी दें, चाहे आप वास्तव में ऐसा चाहते थे या नहीं:

+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young

वेरी वेल, डिफाइन "बेस्ट।"

वर्तमान ${PATH}में सुरक्षित रूप से संलग्न और प्रस्तुत करने का तुच्छ मामला नहीं है जो आमतौर पर इसे बनाया जाता है। जबकि सुविधाजनक और प्रतीत होता है कि समझदार है, इस रूप में वन-लाइनर्स export PATH=$PATH:~/opt/binशैतानी जटिलताओं को आमंत्रित करते हैं:

  • आकस्मिक रूप से सापेक्षिक नाम (जैसे export PATH=$PATH:opt/bin)। जबकि bashऔर zshचुपचाप स्वीकार करते हैं और ज्यादातर में रिश्तेदार dirnames उपेक्षा सबसे मामलों, रिश्तेदार dirnames या तो लगाया जाता हैh या t(और संभवतः अन्य नापाक अक्षर) दोनों कारण करने के लिए शर्मनाक तरीके से खुद को आला Masaki कोबायाशी के पंगु बना लाभदायक 1962 कृति आत्महत्या :

    # Don't try this at home. You will feel great pain.
    $ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
    /usr/local/bin:/usr/bin:arakiri
    $ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
    binanuki/yokai   # Congratulations. Your system is now face-up in the gutter.
  • अकस्मात डुप्लिकेट dirnames।हालांकि ${PATH}डुप्लीमन डायरनेम काफी हद तक सहज हैं, वे अवांछित, बोझिल, हल्के रूप से अक्षम, अशुद्ध डिबगैबिलिटी, और इस उत्तर की तरह ड्राइव वियर को भी बढ़ावा देते हैं। जबकि नंद शैली के एसएसडी पहनने के लिए ( बेशक ) प्रतिरक्षा हैं, HDDs नहीं हैं। हर प्रयास किए गए कमांड पर अनावश्यक फाइल सिस्टम का उपयोग एक ही टेम्पो में अनावश्यक रूप से पढ़ा जाने वाला हेड वियर है। नेस्टेड उपप्रकारों में नेस्टेड गोले को लागू करते समय डुप्लिकेट विशेष रूप से अप्रभावित होते हैं, जिस बिंदु पर सहज रूप से एक-लाइनर की तरह export PATH=$PATH:~/watतेजी से ${PATH}नरक के सातवें सर्कल में विस्फोट होता है PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat। केवल Beelzebubba आपकी मदद कर सकता है यदि आप उस पर अतिरिक्त dirnames संलग्न करते हैं। (अपने कीमती बच्चों के साथ ऐसा न करें। )

  • अकस्मात गायब दिरनाम। फिर से, जबकि लापता ${PATH}दिरनामे काफी हद तक सहज हैं, वे आम तौर पर अवांछित, बोझिल, हल्के से अकुशल हैं, डिबगडेबिलिटी को बाधित करते हैं, और ड्राइव पहनने को बढ़ावा देते हैं।

एगो, ऊपर उल्लिखित शेल फ़ंक्शन की तरह अनुकूल स्वचालन। हमें खुद को खुद से बचाना चाहिए।

लेकिन ... क्यों "+ path.append ()"? क्यों नहीं बस append_path ()?

असंबद्धता के लिए (उदाहरण के लिए, वर्तमान में बाहरी आदेशों के साथ ${PATH} या सिस्टम-वाइड शेल फ़ंक्शन कहीं और परिभाषित), उपयोगकर्ता द्वारा परिभाषित शेल फ़ंक्शन आदर्श उपसर्गों या प्रत्यय द्वारा समर्थित अद्वितीय सब्सट्रिंग के साथ हैं bashऔर zshअन्यथा मानक कमांड बेसेंम्स के लिए निषिद्ध हैं - जैसे, कहते हैं +,।

अरे। यह काम करता हैं। मुझे जज मत करो।

लेकिन ... क्यों "+ path.append ()"? क्यों नहीं "+ path.prepend ()"?

क्योंकि वर्तमान के ${PATH}लिए अपील करना वर्तमान को प्रस्तुत करने की तुलना में अधिक सुरक्षित है ${PATH}, सभी चीजें समान हैं, जो वे कभी नहीं हैं। उपयोगकर्ता-विशिष्ट आदेशों के साथ सिस्टम-वाइड कमांड को ओवरराइड करना सबसे अच्छा और पागल बनाना सबसे खराब हो सकता है। लिनक्स के तहत, उदाहरण के लिए, डाउनस्ट्रीम एप्लिकेशन आमतौर पर GNU कोरुटिल्स की अपेक्षा करते हैं कस्टम गैर-मानक डेरिवेटिव या विकल्प के बजाय आदेशों वेरिएंट की ।

उस ने कहा, ऐसा करने के लिए बिल्कुल वैध उपयोग के मामले हैं। समतुल्य +path.prepend()फ़ंक्शन को परिभाषित करना तुच्छ है। सैंस प्रोलिक्स नेबुलोसिटी, उसके और उसके साझा विवेक के लिए:

+path.prepend() {
    local dirname
    for dirname in "${@}"; do
        dirname="${dirname%/}"
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname}:"* &&
           -d "${dirname}" ]] || continue
        PATH="${dirname}:${PATH}"
    done
    PATH="${PATH%:}"
    export PATH
}

लेकिन ... गिल्स क्यों नहीं?

गिल्स का स्वीकृत उत्तर कहीं और सामान्य रूप से "शेल एग्नॉस्टिक इम्पोटेंट अपेंडेंट" के रूप में सामान्य रूप से इष्टतम है । के आम मामले में bashऔर zshसाथ कोई अवांछनीय सिमलिंक, हालांकि, प्रदर्शन दंड इतना दुख करने के लिए आवश्यक Gentoo ricer मुझ में। यहां तक ​​कि अवांछनीय सीलिंक की उपस्थिति में, यह बहस का विषय है कि क्या प्रति सब्सक्रिप्शन एक से अधिक हैadd_to_PATH() तर्क सिम्पीनल डुप्लिकेट के संभावित सम्मिलन के लायक है।

सख्त उपयोग के मामलों की मांग के लिए, यहां तक ​​कि सिमलिंक डुप्लिकेट को भी समाप्त किया जा सकता है, यह- zshविशिष्ट संस्करण अक्षम कांटे के बजाय कुशल बिल्डरों के माध्यम से ऐसा करता है:

+path.append() {
    local dirname
    for   dirname in "${@}"; do
        dirname="${dirname%/}"
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname:A}:"* &&
           -d "${dirname}" ]] || continue
        PATH="${PATH}:${dirname}"
    done
    PATH="${PATH#:}"
    export PATH
}

मूल के *":${dirname:A}:"*बजाय ध्यान दें *":${dirname}:"*। सहित अन्य अन्य गोले के तहत :Aएक चमत्कारिक zsh-दुखद रूप से अनुपस्थित है bash। बोली के लिए man zshexpn:

A : aसंशोधक के रूप में फ़ाइल का नाम एक पूर्ण पथ में बदल देता है, और फिर realpath(3)प्रतीकात्मक लिंक को हल करने के लिए लाइब्रेरी फ़ंक्शन के माध्यम से परिणाम पास करता है । नोट: realpath(3)जिन सिस्टमों में लाइब्रेरी फंक्शन नहीं है, उन सिम्बॉलिक लिंक्स को हल नहीं किया जाता है, इसलिए वे सिस्टम पर हैं aऔर Aसमकक्ष हैं।

कोई अन्य प्रश्न नही।

आपका स्वागत है। सुरक्षित गोलाबारी का आनंद लें। अब आप इसके लायक हैं।


0

यहाँ मेरा कार्यात्मक-प्रोग्रामिंग-शैली संस्करण है।

  • किसी भी बृहदान्त्र-सीमांकित *PATHचर के लिए काम करता है , न केवल PATH
  • वैश्विक स्थिति तक पहुँच नहीं है
  • केवल इसके दिए गए अपरिवर्तनीय इनपुट के साथ / पर काम करता है
  • एक ही उत्पादन करता है
  • कोई दुष्प्रभाव नहीं
  • संस्मरणात्मक (सिद्धांत रूप में)

इसके अलावा उल्लेखनीय:

  • अज्ञेय के संबंध में export; कॉलर को छोड़ दिया गया है (उदाहरण देखें)
  • शुद्ध bash; कोई फोर्किंग नहीं
path_add () {
  # $ 1: सुनिश्चित करने के लिए तत्व दिए गए पथ स्ट्रिंग में ठीक एक बार है
  # $ 2: मौजूदा पथ स्ट्रिंग मूल्य ("$ पथ", "पथ" नहीं)
  # $ 3 (वैकल्पिक, कुछ भी): यदि दिया गया है, तो $ 1 में जोड़ें; अन्यथा, बहाना
  #
  # उदाहरण:
  # $ निर्यात पथ = $ (path_add '/ opt / bin' "$ PATH")
  # $ CDPATH = $ (path_add '/ संगीत' "$ CDPATH" at_end)

  स्थानीय -r पहले से ही प्रस्तुत करना = "(^ |:) $ {1} ($ | :) :)"
  अगर [["$ 2" = ~ $ पहले से ही]]; फिर
    इको "$ 2"
  एलिफ [[$ # == 3]]; फिर
    गूंज "$ {2}: $ {1}"
  अन्य
    गूंज "$ {1}: $ {2}"
  फाई
}

0

यह स्क्रिप्ट आपको अंत में जोड़ने की अनुमति देती है $PATH:

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

या शुरुआत में जोड़ें $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" ] && [ "$prefix" != "" ] && PATH=$prefix:$PATH
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.