यदि यह पहले से ही नहीं है, तो $ PATH में निर्देशिका जोड़ें


126

क्या किसी ने $ पीएटीएच को एक निर्देशिका जोड़ने के लिए एक बैश फ़ंक्शन लिखा है यदि यह पहले से ही वहां नहीं है?

मैं आमतौर पर कुछ का उपयोग करके पेट में जोड़ता हूं:

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

यदि मैं अपने PATH का निर्माण .bash_profile में करता हूं, तो यह तब तक नहीं पढ़ा जाता है जब तक कि मैं जिस सत्र में हूं वह लॉगिन सत्र नहीं है - जो हमेशा सच होता है। यदि मैं अपने PATH का निर्माण .bashrc में करता हूं, तो यह प्रत्येक सबस्क्रिप्शन के साथ चलता है। इसलिए अगर मैं एक टर्मिनल विंडो लॉन्च करता हूं और फिर स्क्रीन चलाता हूं और फिर एक शेल स्क्रिप्ट चलाता हूं, तो मुझे मिलता है:

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

मैं एक बश फ़ंक्शन बनाने की कोशिश करने जा रहा हूं, add_to_path()जिसे केवल निर्देशिका कहा जाता है यदि यह वहां नहीं है। लेकिन, अगर किसी ने पहले से ही ऐसा लिखा है (या पाया है), तो मैं उस पर समय नहीं बिताऊंगा।


कुछ बुनियादी सुविधाओं के लिए stackoverflow.com/questions/273909/… देखें जो मदद कर सकते हैं।
dmckee


यदि आप समस्या को केवल "यदि पहले से ही नहीं जोड़ रहे हैं" के रूप में समस्या को फ्रेम करते हैं, तो आप उस दिन आश्चर्यचकित होंगे जब दिन की शुरुआत में सम्मिलित आइटम के लिए यह महत्वपूर्ण होगा, लेकिन यह वहाँ हवा नहीं करता है। तत्व को सम्मिलित करने के लिए एक बेहतर दृष्टिकोण होगा, और फिर डुप्लिकेट को हटा दें, इसलिए यदि नई प्रविष्टि पहले से ही थी, तो इसे प्रभावी रूप से शुरुआत में ले जाया जाएगा।
डॉन हैच

जवाबों:


125

मेरे .bashrc से:

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

ध्यान दें कि पैट को पहले से ही निर्यात के रूप में चिह्नित किया जाना चाहिए, इसलिए पुन: निर्यात की आवश्यकता नहीं है। यह जाँचता है कि क्या निर्देशिका मौजूद है और इसे जोड़ने से पहले एक निर्देशिका है, जिसकी आपको परवाह नहीं है।

इसके अलावा, यह नई निर्देशिका को पथ के अंत तक जोड़ता है; शुरुआत में रखने के लिए, PATH="$1${PATH:+":$PATH"}"उपरोक्त PATH=लाइन के बजाय उपयोग करें ।


26
मुझे परवाह है।
डेनिस विलियमसन

4
@ नील: यह काम करता है, क्योंकि यह ":$PATH:"सिर्फ"$PATH"
गॉर्डन डेविसन

3
@GordonDavisson: मैं माफी माँगता हूँ, मेरा परीक्षण गलत था और आप सही हैं।
नील

2
@GordonDavisson घुंघराले ब्रैकेट में सामान का क्या मतलब है। मैं इसे " ${PATH:+"$PATH:"}$ 1" की पहेली नहीं बना सकता
बोटकोडर

5
@ Mark0978: यह वही है जो मैंने समस्या को हल करने के लिए किया था। ${variable:+value}इसका मतलब यह variableहै कि क्या परिभाषित किया गया है और एक गैर-रिक्त मान है, और यदि यह मूल्यांकन का परिणाम देता है value। मूल रूप से, यदि पेटी नॉनब्लांक के साथ शुरू करने के लिए इसे सेट करता है "$PATH:$1"; अगर यह खाली है तो यह इसे सिर्फ "$1"(कोलन की कमी पर ध्यान दें) के लिए सेट करता है ।
गॉर्डन डेविसन

19

गॉर्डन डेविसन के जवाब पर विस्तार करते हुए, यह कई तर्कों का समर्थन करता है

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

तो आप पथपाथ पथ 1 पथ 2 पथ 3 कर सकते हैं ...

प्रस्तुत करने के लिए,

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

पेटाफेंड के समान, आप कर सकते हैं

pathprepend path1 path2 path3 ...


3
यह भी खूब रही! मैंने एक छोटा सा बदलाव किया। 'Pathprepend' फ़ंक्शन के लिए, तर्कों को रिवर्स में पढ़ना सुविधाजनक है, इसलिए आप उदाहरण के लिए कह सकते हैं, pathprepend P1 P2 P3और इसके साथ समाप्त हो सकते हैं PATH=P1:P2:P3। इस व्यवहार पाने के लिए, बदलने for ARG in "$@" doके लिएfor ((i=$#; i>0; i--)); do ARG=${!i}
इश्माएल

धन्यवाद @ishmael, अच्छा सुझाव, मैंने उत्तर संपादित किया। मुझे पता है कि आपकी टिप्पणी दो साल से अधिक पुरानी है, लेकिन मैं तब से वापस नहीं आया हूं। मुझे यह पता लगाना है कि अपने इनबॉक्स में आने के लिए स्टैक एक्सचेंज ई-मेल कैसे प्राप्त करें!
गुइल्यूम पेरौल्ट-आर्कबोल्ट

14

यहाँ से कुछ मेरा उत्तर करने के लिए इस सवाल का डौग हैरिस समारोह की संरचना के साथ संयुक्त। यह बैश नियमित अभिव्यक्ति का उपयोग करता है:

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

इसने मेरे लिए काम किया$1${1}
आंद्रेई

@Andrei: हाँ, इस उदाहरण में ब्रेसिज़ अनावश्यक हैं। मुझे यकीन नहीं है कि मैंने उन्हें क्यों शामिल किया।
डेनिस विलियमसन

10

चयनित उत्तर के लिए टिप्पणियों में इसे रखें, लेकिन टिप्पणियां PRE स्वरूपण का समर्थन नहीं करती हैं, इसलिए यहां उत्तर जोड़ें:

@ गोर्डन-डेविसन मैं अनावश्यक उद्धरण और सहमति का बहुत बड़ा प्रशंसक नहीं हूं। मान लें कि आप bash संस्करण> = 3 का उपयोग कर रहे हैं, तो आप इसके बजाय bash के बिल्ट इन regexs का उपयोग कर सकते हैं और करें:

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

यह उन मामलों को सही ढंग से संभालता है जहां निर्देशिका या पथ में स्थान होते हैं। कुछ सवाल यह भी है कि क्या बैश का बिल्ट इन रेक्सक्स इंजन इतना धीमा है कि यह नेट कंसट्रक्शन और इंटरपोलेशन की तुलना में कम कुशल हो सकता है जो कि आपका संस्करण करता है, लेकिन किसी तरह यह सिर्फ मेरे लिए अधिक सौंदर्यवादी रूप से स्वच्छ महसूस करता है।


1
टिप्पणियाँ formatting using the backtickकेवल समर्थन करती हैं, लेकिन आपको कोई भी अच्छा पैराग्राफ नियंत्रण नहीं मिलता है।
बोटकोडर

यह अंत में अतिरिक्त डालता है। मौजूदा स्थानों को ओवरराइड करने के लिए शुरुआत में जोड़ना अक्सर वांछनीय होता है।
डेनिस विलियमसन

@DennisWilliamson यह एक उचित बिंदु है, हालांकि मैं डिफ़ॉल्ट व्यवहार के रूप में सिफारिश नहीं करेंगे। यह पता लगाना मुश्किल नहीं है कि प्रीपेन्ड के लिए कैसे बदलना है।
क्रिस्टोफर स्मिथ

@ChristopherSmith - पुनः: unnecessary quotingतात्पर्य है कि आप समय से पहले जानते हैं कि $PATHयह अशक्त नहीं है। "$PATH"यह ठीक है कि क्या पथ शून्य है या नहीं। इसी तरह अगर $1ऐसे अक्षर होते हैं जो कमांड पार्सर को भ्रमित कर सकते हैं। रेक्स को उद्धरणों में रखने से "(^|:)$1(:|$)"रोकता है।
जेसी चिशोल्म

@ जेसे शीशमोल: वास्तव में, मेरा मानना ​​है कि क्रिस्टोफर की बात यह है कि नियम अलग हैं [[और ]]। मैं वह सब कुछ उद्धृत करना पसंद करता हूं जिसे संभवतः उद्धृत करने की आवश्यकता हो सकती है, जब तक कि यह विफल न हो जाए, लेकिन मेरा मानना ​​है कि वह सही है, और उस उद्धरण की वास्तव में आवश्यकता नहीं है $PATH। दूसरी ओर, यह मुझे लगता है कि आप के बारे में सही हैं $1
स्कॉट

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 की शुरुआत में एक बार $ HOME / बिन की आवश्यकता होती है और कहीं नहीं, कोई विकल्प स्वीकार नहीं करते हैं।


धन्यवाद, यह एक अच्छा सुरुचिपूर्ण समाधान है, लेकिन मैंने पाया कि मुझे ऐसा करना था PATH=${PATH/"... बल्कि PATH=${PATH//"... इसे काम करने के लिए।
मार्क बूथ

डबल-स्लैश फॉर्म को किसी भी संख्या से मेल खाना चाहिए; एकल स्लैश केवल पहले से मेल खाता है (बैश मैन पेज में "पैटर्न प्रतिस्थापन" के लिए खोज)। निश्चित नहीं है कि यह काम क्यों नहीं किया ...
andybuckley

यह $1केवल एक ही प्रविष्टि (कोई कॉलन) के असामान्य मामले में विफल रहता है । प्रवेश दोगुना हो जाता है।
डेनिस विलियमसन

यह भी आक्रामक रूप से हटाता है जैसा कि पीटरएस 6 जी द्वारा बताया गया है ।
डेनिस विलियमसन

6

यहां एक वैकल्पिक समाधान है जिसमें अनावश्यक प्रवेश को हटाने का अतिरिक्त लाभ है:

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

इस फ़ंक्शन के लिए एकल तर्क PATH से जुड़ा हुआ है, और उसी स्ट्रिंग का पहला उदाहरण मौजूदा पथ से हटा दिया गया है। दूसरे शब्दों में, यदि निर्देशिका पहले से ही पथ में मौजूद है, तो इसे डुप्लिकेट के रूप में जोड़े जाने के बजाय सामने की ओर प्रचारित किया जाता है।

फ़ंक्शन यह सुनिश्चित करने के लिए एक कॉलन को पथ पर प्रीपेड करके काम करता है कि सभी प्रविष्टियों के सामने एक कोलन है, और फिर उस प्रविष्टि के साथ मौजूदा पथ में नई प्रविष्टि को हटा दिया जाए। अंतिम भाग बैश के ${var//pattern/sub}संकेतन का उपयोग करके किया जाता है; देख बैश पुस्तिका अधिक जानकारी के लिए।


अच्छा विचार; त्रुटिपूर्ण कार्यान्वयन। विचार करें कि क्या होता है यदि आपके पास पहले से ही /home/robertआपके PATHऔर आपके पास है pathadd /home/rob
स्कॉट

5

यहाँ मेरा है (मुझे विश्वास है कि यह मेरी पुरानी लैब के sysadmin ऑस्कर द्वारा वर्षों पहले लिखा गया था, इसका श्रेय सभी को जाता है), यह उम्र के लिए मेरे bashrc में था। इसमें आपको नई निर्देशिका को वांछित के रूप में प्रस्तुत करने या जोड़ने की अनुमति देने का अतिरिक्त लाभ है:

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

उपयोग:

$ 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

प्रस्तुत करने के लिए, मुझे @ रसेल समाधान पसंद है, लेकिन एक छोटा सा बग है: यदि आप "/ बिन" जैसे किसी चीज़ को "/ sbin: / usr / bin: / var / usr / bin: usr / स्थानीय" के रूप में प्रस्तुत करने का प्रयास करते हैं / बिन: / usr / sbin "यह" की जगह लेता है "/ bin:" 3 बार (जब यह वास्तव में बिल्कुल मेल नहीं खाता था)। इसके लिए एक फिक्स का संयोजन @ gordon-davisson से लागू समाधान के साथ, मुझे यह मिला:

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

इस तरह के एक सरल उपनाम को नीचे करना चाहिए:

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

यह सब करता है: चरित्र पर पथ को विभाजित किया जाता है और आपके द्वारा पास किए गए तर्क के खिलाफ प्रत्येक घटक की तुलना करें। एक पूर्ण लाइन मैच के लिए grep चेक, और गिनती को प्रिंट करता है।

नमूना उपयोग:

$ 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

AddToPath या कुछ समान उपनाम / फ़ंक्शन के साथ इको कमांड को बदलें।


"Grep -x" का उपयोग करना संभवतः मेरे बैश फ़ंक्शन में लगाए गए लूप की तुलना में तेज़ है।
डग हैरिस


2

यहाँ मैं कोड़ा है:

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
}

अब मेरे पास .bashrc:

add_to_path /usr/local/mysql/bin

अपडेट किया गया संस्करण निम्नलिखित टिप्पणी के बारे में है कि मेरे मूल स्थान के साथ निर्देशिकाओं को कैसे नहीं संभालेंगे ( मुझे इस प्रश्न का उपयोग करने के लिए धन्यवाद 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
यह विफल हो सकता है यदि कोई निर्देशिका का नाम पहले से ही में PATHरिक्त स्थान हैं, *, ?, या [... ]
स्कॉट

अच्छी बात है ... लेकिन मैं एक पुराने स्कूल का लाइनक्स आदमी हूं और कभी इसमें व्हाट्सएप के साथ एक पथ का उपयोग नहीं करूंगा :-)
डग हैरिस

आपके लिए अच्छा है, उनके नाम पर व्हाट्सएप के साथ चीजें न बनाएं। कोड लिखने के लिए आप पर शर्म आती है कि वे मौजूद होने पर उन्हें संभाल नहीं सकते। और "एक पुराने स्कूल लिनक्स आदमी" के साथ क्या करना है? विंडोज़ ने विचार को लोकप्रिय किया (धन्यवाद, Documents and Settingsऔर Program Files), लेकिन विंडिक्स के अस्तित्व में आने से पहले यूनिक्स ने व्हॉट्सएप वाले मार्गनामों का समर्थन किया है ।
स्कॉट

2

मैं थोड़ा हैरान हूं कि किसी ने अभी तक इसका उल्लेख नहीं किया है, लेकिन आप readlink -fसापेक्ष पथों को निरपेक्ष पथों में बदलने के लिए उपयोग कर सकते हैं , और उन्हें इस तरह से पाथ में जोड़ सकते हैं।

उदाहरण के लिए, गिलौम पेरौल्ट-आर्कबॉल्ट के जवाब में सुधार करने के लिए,

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

हो जाता है

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. मूल बातें - यह क्या अच्छा है?

readlink -fआदेश (अन्य बातों के अलावा) एक निरपेक्ष पथ के लिए एक रिश्तेदार पथ परिवर्तित कर देंगे। इससे आप कुछ ऐसा कर सकते हैं

$ cd / path / to / my / bin / dir
$ पाथपेंड 
$ गूंज "$ पाथ"
<your_old_path> : / path / to / my / bin / dir

2. हम दो बार पाथे होने के लिए परीक्षा क्यों देते हैं?

खैर, उपरोक्त उदाहरण पर विचार करें। यदि उपयोगकर्ता निर्देशिका से दूसरी बार कहता है , तो होगा । बेशक, इसमें उपस्थित नहीं होंगे । लेकिन फिर ( पहले से ही पूर्ण पथ के बराबर ) पर सेट किया जाएगा , जो पहले से ही अंदर है । इसलिए हमें दूसरी बार जोड़ने से बचने की आवश्यकता है ।pathappend ./path/to/my/bin/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH

शायद अधिक महत्वपूर्ण बात यह है कि readlinkजैसा कि इसके नाम का अर्थ है, एक प्रतीकात्मक लिंक को देखना और इसमें शामिल होने वाले पथनाम को पढ़ना (जैसे, अंक)। उदाहरण के लिए:

$ 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

अब, यदि आप कहते हैं pathappend /usr/lib/perl/5.14, और आप पहले से ही /usr/lib/perl/5.14अपने पेट में हैं, ठीक है, यह ठीक है; हम इसे वैसे ही छोड़ सकते हैं जैसे यह है। लेकिन, अगर /usr/lib/perl/5.14आपके पथ में पहले से ही नहीं है, हम कहते हैं readlinkऔर मिल ARGA= /usr/lib/perl/5.14.2, और फिर हम जोड़ने कि करने के लिए PATH। लेकिन एक मिनट प्रतीक्षा करें - यदि आपने पहले ही कहा था pathappend /usr/lib/perl/5.14, तो आपके पास पहले से ही /usr/lib/perl/5.14.2आपके पेट में है, और, फिर से, हमें इसे PATHदूसरी बार जोड़ने से बचने के लिए जांचना होगा ।

3. डील क्या है if ARGA=$(readlink -f "$ARG")?

यदि यह अस्पष्ट है, तो यह रेखा परीक्षण करती है कि क्या readlinkसफल होता है। यह सिर्फ अच्छा, रक्षात्मक प्रोग्रामिंग अभ्यास है। यदि हम कमांड n से आउटपुट मी का उपयोग कमांड  n (जहाँ m  <  n ) के भाग के रूप में करने जा रहे हैं  , तो यह जाँचना समझदारी है कि क्या कमांड  m विफल हुआ है और किसी तरह से इसे संभालता है। मुझे नहीं लगता कि यह संभव है कि विफल होगा - लेकिन, जैसा कि ओएस एक्स और अन्य जगहों से एक मनमाना फ़ाइल के पूर्ण पथ को पुनः प्राप्त करने के लिए चर्चा की गई है, एक GNU आविष्कार है। यह POSIX में निर्दिष्ट नहीं है, इसलिए मैक ओएस, सोलारिस और अन्य गैर-लिनक्स यूनिक्स में इसकी उपलब्धता संदिग्ध है। (वास्तव में, मैं सिर्फ एक टिप्पणी पढ़ता हूं जो कहती है "readlinkreadlinkreadlink -fमैक ओएस एक्स 10.11.6 पर काम करने के लिए प्रतीत नहीं होता है, लेकिन realpathबॉक्स से बाहर काम करता है। ”तो, यदि आप एक ऐसी प्रणाली पर हैं readlink, जो आपके पास नहीं है , या जहां readlink -fकाम नहीं करता है, तो आप इसे संशोधित करने में सक्षम हो सकते हैं। स्क्रिप्ट का उपयोग करें realpath।) एक सुरक्षा जाल स्थापित करके, हम अपने कोड को कुछ अधिक पोर्टेबल बनाते हैं।

बेशक, यदि आप एक ऐसी प्रणाली पर हैं जिसमें readlink(या  realpath) नहीं है , तो आप नहीं करना चाहते हैं ।pathappend .

दूसरा -dपरीक्षण ( [ -d "$ARGA" ]) वास्तव में शायद अनावश्यक है। मैं किसी भी परिदृश्य के बारे में नहीं सोच सकता जहाँ $ARGएक निर्देशिका है और readlinkसफल है, लेकिन  $ARGAएक निर्देशिका नहीं है। मैंने ifतीसरे कथन को बनाने के लिए पहले कथन को कॉपी-पेस्ट किया और मैंने -dआलस से वहाँ से परीक्षा छोड़ दी  ।

4. कोई अन्य टिप्पणियाँ?

हाँ। यहां कई अन्य उत्तरों की तरह, यह एक परीक्षण करता है कि क्या प्रत्येक तर्क एक निर्देशिका है, अगर यह है तो इसे संसाधित करता है, और इसे अनदेखा करता है यदि यह नहीं है। यह (या नहीं हो सकता) यदि आप उपयोग कर रहे हैं पर्याप्त हो सकता है pathappend "में केवल ." (जैसे फ़ाइलों .bash_profileऔर .bashrc) और अन्य लिपियों। लेकिन, जैसा कि इस उत्तर में दिखाया गया है (ऊपर), यह अंतःक्रियात्मक रूप से उपयोग करने के लिए पूरी तरह से संभव है। अगर आप ऐसा करेंगे तो आप बहुत हैरान होंगे

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

आप नोटिस किया कि मैंने कहा कि nysql में pathappendआदेश के बजाय mysql? और pathappendइसने कुछ नहीं कहा; यह सिर्फ चुपचाप गलत तर्क को नजरअंदाज कर दिया?

जैसा कि मैंने ऊपर कहा, त्रुटियों को संभालने के लिए यह अच्छा अभ्यास है। यहाँ एक उदाहरण है:

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) आपको उद्धरण जोड़ना चाहिए readlink -f "$ARG":। (2) मुझे नहीं पता कि ऐसा क्यों होगा (विशेषकर -d "$ARG"परीक्षण के सफल होने के बाद ), लेकिन आप परीक्षण करना चाहते हैं कि क्या readlinkविफल हुआ। (3) आप readlinkएक प्राथमिक लिंक नाम को "वास्तविक फ़ाइल नाम" का प्रतीकात्मक रूप देना चाहते हैं। यदि (उदाहरण के लिए) /binएक प्रतीकात्मक लिंक है /bin64, तो बार-बार कॉल करने pathappend /binसे PATH कहा जा सकता है …:/bin64:/bin64:/bin64:/bin64:…। आपको शायद (यह भी) जांचना चाहिए कि क्या नया मूल्य $ARGपहले से है PATH
स्कॉट

(1) अच्छा अवलोकन, मैंने इसे ठीक किया। (२) किस मामले में रीडलिंक विफल होगा? यह मानते हुए कि एक रास्ता सही है और यह एक वैध स्थान को संदर्भित करता है। (3) मुझे यकीन नहीं है कि क्या रीडिंकल के प्राथमिक कार्य को निर्धारित करता है, मुझे विश्वास है कि अधिकांश (यदि सभी नहीं हैं?) एक यूनिक्स फाइल सिस्टम में पथ को 2 प्रकार के लिंक, प्रतीकात्मक लिंक और हार्ड लिंक में विभाजित किया जा सकता है। डुप्लिकेट पथ प्रविष्टि के लिए आप सही हैं, लेकिन मेरे उत्तर का उद्देश्य यह जोड़ना नहीं था (जैसा कि मैंने देखा है कि अन्य उत्तर पहले ही इसका उल्लेख कर चुके हैं)। केवल यही कारण है कि मैं अभी तक एक और जवाब जोड़ रहा हूं कि मुझे कुछ ऐसा योगदान देना है जो मुझे लगा कि पहले से योगदान नहीं दिया गया था
qwertyzw

(२) मेरा मतलब है, यदि कम से कम कमांड का नाम इसके उद्देश्य पर निहित / संकेतित है, तो रीडलिंक में 'लिंक' या तो हार्ड या सॉफ्ट लिंक को संदर्भित कर सकता है। हालाँकि आप सही हैं: मैन रीडिंकल कहते हैं कि 'रीडलिंक - प्रिंटेड सिम्बॉलिक लिंक्स या कैनोनिकल फ़ाइल नाम', .मेरे उदाहरण में मेरा मानना ​​है कि इसे कैनोनिकल फ़ाइल नाम माना जा सकता है। सही बात?
qwertyzw

(1) जो लोग सांकेतिक लिंक को समझते हैं, उनके readlinkनाम का स्पष्ट रूप से उद्देश्य है - यह एक प्रतीकात्मक लिंक को देखता है और इसमें शामिल पथनाम को पढ़ता है (यानी, अंक)। (२) ठीक है, मैंने कहा कि मुझे नहीं पता था कि readlinkअसफल क्यों होगा। मैं सामान्य बिंदु बना रहा था कि अगर किसी स्क्रिप्ट या फ़ंक्शन में कई कमांड होते हैं, और कमांड  n को भयावह रूप से विफल होने की गारंटी दी जाती है (या बिल्कुल भी समझ में नहीं आता है) यदि कमांड  m विफल हुआ है (जहां m  <  n ), यह विवेकपूर्ण अच्छा अभ्यास है जाँच करें कि क्या कमांड m विफल हुआ और किसी तरह से इसे संभाल लें - बहुत कम से कम,… (Cont'd)
स्कॉट

(Cont'd) ... डायग्नोस्टिक के साथ स्क्रिप्ट / फ़ंक्शन को निरस्त करें। परिकल्पित, readlinkविफल हो सकता है यदि (क) निर्देशिका में अपनी कॉल के बीच का नाम बदला या (अन्य प्रक्रिया द्वारा) नष्ट किया गया testऔर readlink, या (ख) यदि /usr/bin/readlinkहटा दिया गया था (या भ्रष्ट)। (३) आपको मेरी बात याद आ रही है। मैं आपको अन्य उत्तर (ओं) की नकल करने के लिए प्रोत्साहित नहीं कर रहा हूँ; मैं कह रहा हूँ कि, यह जाँचने से कि क्या मूल ARG(कमांड लाइन से) पहले से ही है PATH, लेकिन नए (से आउटपुट ) के लिए चेक को दोहराना नहीं है , आपका उत्तर अधूरा है और इसलिए गलत है। … (Cont'd)ARGreadlink
स्कॉट

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

1

यह तरीका ठीक काम करता है:

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

0

मेरे संस्करण खाली रास्तों के बारे में कम सावधानी बरतते हैं और कुछ पोस्ट किए गए रास्तों की तुलना में वैध और निर्देशिकाओं पर जोर देते हैं, लेकिन मुझे प्रीपेन्ड / एपेंड / क्लीन / यूनीक-इफ / आदि का एक बड़ा-ईश संग्रह मिलता है। पथ के हेरफेर के लिए शेल फ़ंक्शन उपयोगी होते हैं। पूरे बहुत से, उनकी वर्तमान स्थिति में, यहाँ हैं: http://pastebin.com/xS9sgQsX (प्रतिक्रिया और सुधार आपका स्वागत है!)


0

आप एक पर्ल एक लाइनर का उपयोग कर सकते हैं:

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;' "$@"
}

यहाँ यह बाश में है:

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

यदि कोई आपूर्ति नहीं की जाती है तो मैं वर्तमान डायर का उपयोग करने के लिए गॉर्डन डेविसन के उत्तर को थोड़ा संशोधित करता हूं । तो आप बस paddउस निर्देशिका से कर सकते हैं जिसे आप अपने PATH में जोड़ना चाहते हैं।

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

0

आप जाँच सकते हैं कि कोई कस्टम चर सेट किया गया है, अन्यथा इसे सेट करें और फिर नई प्रविष्टियाँ जोड़ें:

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

बेशक, इन प्रविष्टियों को अभी भी डुप्लिकेट किया जा सकता है यदि किसी अन्य स्क्रिप्ट द्वारा जोड़ा जाता है, जैसे कि /etc/profile


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" ] && PATH=$prefix:$PATH
}

0

यहाँ एक POSIX- आज्ञाकारी तरीका है।

# 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"
        }
}

यह इस सवाल का जवाब है और यहाँ पर mike511 के जवाब में गिलौम पेरौल्ट- आर्कबॉल्ट के जवाब से सिहर उठता है

अद्यतन 2017-11-23: फिक्स्ड बग प्रति @ वर्ग


मैं इसे डिफ़ॉल्ट रूप से प्रीपेडिंग और पोस्टपेडिंग (एपेंडिंग) के बीच चुनने के लिए कमांड-लाइन विकल्प प्रदान करने के लिए इसे अपग्रेड करने जा रहा था। लेकिन फिर मैंने सोचा: यह कुछ हद तक बिना किसी स्पष्टीकरण के एक गंभीर कोड है। (और सच है कि आप दो कार्य है, जहां पथ बदल देता है और अपनी नई मूल्य गूँज, और अन्य कब्जा कि उत्पादन और यह पथ के लिए फिर से प्रदान करती है , (जारी) सिर्फ एक अनावश्यक जटिलता है।) ...
स्कॉट

(Cont'd) ... और फिर मैंने देखा कि लिंक गलत थे। (और मुझे यकीन नहीं है कि आप उन लोगों को क्यों दोषी ठहरा रहे हैं? आपको लगता है कि उनके उत्तरों से बहुत अधिक नकल नहीं हुई है।) और फिर मैंने देखा कि कोड गलत था। मुझे लगता है कि यह एक अच्छी तरह से गठित पेट को बनाए रखने का एक ठीक काम करता है , लेकिन इसकी कोई गारंटी नहीं है कि यह पहले से ही अच्छी तरह से बनाया गया है, खासकर यदि आपके पास एक अप्रकाशित है /etc/profile। जिस निर्देशिका को आप PATH में जोड़ने की कोशिश कर रहे हैं, वह पहले से ही एक से अधिक बार हो सकती है , और उस पर आपका कोड चोक हो सकता है। … (Cont'd)
स्कॉट

(जारी) ... उदाहरण के लिए, यदि आप पहले जोड़ें करने के लिए प्रयास /a/ckकरने के लिए /b:/a/ck:/tr:/a/ck, आपको मिल /a/ck:/b:/a/ck:/tr:/tr:/a/ck
स्कॉट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.