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


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

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

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

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

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

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


116
2017-09-11 16:19


मूल


देख stackoverflow.com/questions/273909/... कुछ बुनियादी ढांचे के लिए जो मदद कर सकते हैं। - dmckee
unix.stackexchange.com/questions/4965/... - Ciro Santilli 新疆改造中心 六四事件 法轮功
यदि आप समस्या को "केवल पहले से नहीं जोड़ते हैं" के रूप में फ्रेम करते हैं, तो आप उस समय आश्चर्यचकित होने जा रहे हैं जब दिन आता है जब सम्मिलित आइटम के लिए शुरुआत में होना महत्वपूर्ण है लेकिन यह वहां नहीं चलता है। तत्व को सम्मिलित करने के लिए एक बेहतर तरीका होगा, और उसके बाद डुप्लिकेट हटा दें, इसलिए यदि नई प्रविष्टि पहले से मौजूद थी तो इसे प्रभावी रूप से शुरुआत में स्थानांतरित कर दिया जाएगा। - Don Hatch


जवाब:


मेरे .bashrc से:

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

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

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


117
2017-09-12 03:08



मुझे परवाह है। - Dennis Williamson
@Neil: यह काम करता है, क्योंकि यह तुलना करता है ":$PATH:" बस के बजाय "$PATH" - Gordon Davisson
@ गॉर्डन डेविसन: मैं क्षमा चाहता हूं, मेरा परीक्षण गलत था और आप सही हैं। - Neil
@GordonDavisson घुंघराले ब्रैकेट में सामान का बिंदु क्या है। मैं इसे समझने के लिए प्रतीत नहीं कर सकता "${PATH:+"$PATH:"}$ 1 " - boatcoder
@ मार्क 0 9 78: यही समस्या है जो मैंने समस्या को ठीक करने के लिए किया था। ${variable:+value} मतलब है कि जांचें variable परिभाषित किया गया है और इसमें एक खाली मूल्य है, और यदि यह मूल्यांकन का परिणाम देता है value। असल में, यदि पैथ इसके साथ शुरू करने के लिए nonblank है इसे सेट करता है "$PATH:$1"; यदि यह खाली है तो यह इसे बस सेट करता है "$1" (एक कोलन की कमी ध्यान दें)। - Gordon Davisson


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

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

तो आप pathappend path1 path2 path3 कर सकते हैं ...

पूर्ववत करने के लिए,

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

Pathappend के समान, आप कर सकते हैं

pathprepend path1 path2 path3 ...


19
2018-05-15 18:42



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


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

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

12
2017-09-11 19:11



यह केवल मेरे लिए काम किया $1 के बजाय ${1} - Andrei
@Andrei: हाँ, इस उदाहरण में ब्रेसिज़ अनावश्यक हैं। मुझे यकीन नहीं है कि मैंने उन्हें क्यों शामिल किया। - Dennis Williamson


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

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

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

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


10
2018-03-02 18:20



टिप्पणियाँ समर्थन formatting using the backtick केवल लेकिन आपको कोई सभ्य पैराग्राफ नियंत्रण नहीं मिलता है। - boatcoder
यह अंत में जोड़ देता है। मौजूदा स्थानों को ओवरराइड करने के लिए शुरुआत में जोड़ना अक्सर वांछनीय होता है। - Dennis Williamson
@ डेनिसविल्लियमसन यह एक उचित बिंदु है, हालांकि मैं इसे डिफ़ॉल्ट व्यवहार के रूप में अनुशंसा नहीं करता। प्रीपेन्ड के लिए कैसे बदलाव करना है यह समझना मुश्किल नहीं है। - Christopher Smith
@ क्रिस्टोफर स्मिथ - पुनः: unnecessary quoting इसका मतलब है कि आप समय से पहले जानते हैं $PATH निरर्थक नहीं है। "$PATH" यह ठीक है कि पैट शून्य है या नहीं। इसी तरह अगर $1 ऐसे वर्ण हैं जो कमांड पार्सर को भ्रमित कर सकते हैं। उद्धरण में regex डाल "(^|:)$1(:|$)" उसे रोकता है। - Jesse Chisholm
@ जेसे चिश्ल्म: दरअसल, मेरा मानना ​​है कि क्रिस्टोफर का मुद्दा यह है कि नियम अलग-अलग हैं [[ तथा ]]। मैं उन सभी चीजों को उद्धृत करना पसंद करता हूं जिन्हें संभावित रूप से उद्धृत करने की आवश्यकता हो सकती है, जब तक कि यह असफल न हो, लेकिन मेरा मानना ​​है कि वह सही है, और वास्तव में उद्धरण वास्तव में नहीं हैं जरूरत है चारों ओर $PATH। दूसरी तरफ, ऐसा लगता है कि आप सही हैं $1। - Scott


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
}

जब आपको अपने $ पाथ की शुरुआत में एक बार $ HOME / bin की आवश्यकता होती है और कहीं और नहीं, तो कोई विकल्प स्वीकार नहीं करें।


6
2017-08-17 13:31



धन्यवाद, यह एक अच्छा सुरुचिपूर्ण समाधान है, लेकिन मैंने पाया कि मुझे करना है PATH=${PATH/"... बजाय PATH=${PATH//"... इसे काम करने के लिए। - Mark Booth
डबल-स्लैश फॉर्म किसी भी मिलान से मेल खाना चाहिए; एकल स्लैश केवल पहले से मेल खाता है (बैश मैन पेज में "पैटर्न प्रतिस्थापन" की खोज)। यकीन नहीं है कि यह क्यों काम नहीं किया ... - andybuckley
यह असामान्य मामले में विफल रहता है $1 एकमात्र प्रवेश (कोई कॉलन) नहीं है। प्रवेश दोगुना हो जाता है। - Dennis Williamson
जैसा कि द्वारा इंगित किया गया है, यह भी आक्रामक रूप से हटा देता है PeterS6g। - Dennis Williamson


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

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

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

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


6
2018-01-21 12:29



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


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

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
2017-08-17 18:57





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

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
}

5
2017-11-19 02:28





नीचे दिए गए इस तरह की एक साधारण उपनाम चाल करना चाहिए:

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

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


4
2017-09-11 17:26



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


देख Csh में पथ चर डुप्लिकेट से कैसे रखें? इस प्रश्न के उत्तर के एक सेट के लिए StackOverflow पर।


2
2017-09-11 19:47





यहां मैंने जो चाबुक किया है:

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
}

2
2017-09-11 18:03



यह विफल हो सकता है अगर कोई निर्देशिका नाम पहले से ही है PATH सफेद जगह है, *, ?, या [...]। - Scott
अच्छा बिंदु ... लेकिन मैं एक पुराना स्कूल लिनक्स लड़का हूं और कभी भी इसमें व्हाइटस्पेस वाला पथ नहीं उपयोग करूंगा :-) - Doug Harris
आपके नामों में सफेद जगहों के साथ चीजें नहीं बनाने के लिए, आपके लिए अच्छा है। कोड लिखने के लिए आप पर शर्म आती है जो मौजूद होने पर उन्हें संभाल नहीं सकती है। और "पुराने स्कूल लिनक्स लड़के" के साथ क्या करना है? विंडोज़ हो सकता है लोकप्रिय बनाया विचार (धन्यवाद, Documents and Settings तथा Program Files), लेकिन यूनिक्स है समर्थित Windoze अस्तित्व से पहले से व्हाइटस्पेस युक्त पथनाम। - Scott