फ़ाइल के अंत में कुछ लाइन कैसे जोड़ें, अगर यह अभी तक नहीं है?


10

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

आम तौर पर मैं ऐसा कुछ करता हूँ:

cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:\$PATH
EOF

यह भी संभव है कि इसे ansible ( line+ insertafter=EOF+ regexp) के माध्यम से किया जाए , लेकिन यह एक और कहानी है।

Vi / ex में मैं कुछ ऐसा कर सकता था:

ex +'$s@$@\rexport PATH=\~/.composer/vendor/bin:$PATH@' -cwq ~/.bashrc

लेकिन फिर मैं कैसे जांचूं कि क्या लाइन पहले से ही है (और इस तरह कुछ भी नहीं) आदर्श रूप से एक ही लाइन को दोहराए बिना?

या शायद पूर्व संपादक में ऐसा करने के लिए कुछ आसान तरीका है?


क्या आप इसे आउटसोर्स नहीं कर सकते? grep -Fq 'export PATH=~/.composer/vendor/bin:$PATH' ~/.bashrc || ex ...(या cat, उस बात के लिए)?
मूरू

मेरा मानना ​​है कि यह इस दृष्टिकोण के समान कुछ हो सकता है , लेकिन विपरीत (जब स्ट्रिंग नहीं है, तो कुछ करें)।
kenorb

ex ~/.bashrc -c "if search('export PATH=\~\/.composer\/vendor\/bin:\$PATH')>0 | norm quit | endif | norm Aexport PATH=~/.composer/vendor/bin:$PATH"
एलेक्स क्रॉल

1
ध्यान दें कि exportएक कमांड है , इसलिए शेष पंक्ति एक शेल शब्द है, असाइनमेंट नहीं है। इसलिए एक चर असाइनमेंट (जो उपयोग नहीं करता है export) के विपरीत , आपको दोहरे उद्धरण चिह्नों की आवश्यकता है या यह व्हाट्सएप पर टूट जाएगा । यह भी देखें कि कैसे सही ढंग से पथ में एक रास्ता जोड़ सकते हैं
वाइल्डकार्ड

1
मुझे वह वास्तविक लिंक मिला जो मैं कल ढूंढ रहा था (हालाँकि उपरोक्त लिंक भी अच्छे हैं)। क्या स्थानीय वैरिएबल असाइनमेंट के लिए उद्धरण आवश्यक हैं?
वाइल्डकार्ड

जवाबों:


6

यदि आप बुलेटप्रूफ चाहते हैं , तो आप शायद जटिल विकल्पों की तुलना में कुछ अधिक पोर्टेबल चाहते हैं। मैं POSIX सुविधाओंex से चिपकेगा और इसे बेवकूफ़-सरल बनाऊंगा: बस लाइन को हटा दें यदि यह वहां है (चाहे कितनी बार हो), इसे फ़ाइल के अंत में जोड़ें, फिर सहेजें और बाहर निकलें:

ex -sc 'g/^export PATH=\~\/\.composer\/vendor\/bin:\$PATH$/d
$a
export PATH=~/.composer/vendor/bin:$PATH
.
x' ~/.bashrc

मैंने जोड़ा मजबूती के लिए रेगेक्स को लंगर डाला, हालांकि मुझे लगता है कि यह गलती से इस रेगेक्स से मेल खाना असंभव है । (एंकर का अर्थ है उपयोग करना ^और $इसलिए रेगेक्स केवल तभी मैच करेगा जब यह पूरी लाइन से मेल खाता है ।)

ध्यान दें कि +cmdवाक्य रचना POSIX द्वारा आवश्यक नहीं है, न ही कई -cतर्कों की अनुमति देने की सामान्य विशेषता है ।


ऐसा करने के लिए अन्य सरल तरीकों की एक भीड़ है । उदाहरण के लिए, फ़ाइल के अंत में लाइन जोड़ें, फिर बाहरी UNIX फ़िल्टर के माध्यम से फ़ाइल की अंतिम दो पंक्तियाँ चलाएँ uniq:

ex -sc '$a
export PATH=~/.composer/vendor/bin:$PATH
.
$-,$!uniq
x' input

यह बहुत साफ और सरल है, और पूरी तरह से POSIX- अनुरूप भी है। यह बाहरी पाठ फ़िल्टरिंग और POSIX- निर्दिष्ट शेल उपयोगिता केex लिए एस्केप फीचर का उपयोग करता हैuniq

लब्बोलुआब यह है, है exहै डिज़ाइन किया गया यथा-स्थान फ़ाइल संपादन के लिए है और यह अब तक का सबसे पोर्टेबल तरीका है कि पूरा करने के लिए है एक गैर-सहभागी फैशन में। यह मूल भी बनाता है vi, वास्तव में - नाम vi"दृश्य संपादक" के लिए है, और गैर-दृश्य संपादक इसे बनाया गया था ex ।)


और भी सरलता के लिए (और इसे एक पंक्ति में कम करने के लिए), printfकमांड भेजने के लिए उपयोग करें ex:

printf %s\\n '$a' 'export PATH=~/.composer/vendor/bin:$PATH' . '$-,$!uniq' x | ex input

संबंधित: vi.stackexchange.com/q/6269/4676
Wildcard

2

एक संभावित समाधान यह करने के लिए एक फ़ंक्शन बनाना है:

function! AddLine()

    let l:res = 0
    g/export PATH=\~\/.composer\/vendor\/bin:\\\$PATH/let l:res = l:res+1

    if (l:res == 0)
        normal G
        normal oexport PATH=~/.composer/vendor/bin:\$PATH
    endif

endfunction

पहले हम एक स्थानीय वैरिएबल बनाते हैं l:resजिसका उपयोग लाइन की घटनाओं की संख्या को गिनने के लिए किया जाएगा।

हम globalकमांड का उपयोग करते हैं : प्रत्येक बार जब लाइन का मिलान किया जाता है, l:resतो वृद्धि की जाती है।

अंत में अगर l:resअभी भी 0 है तो इसका मतलब है कि लाइन फाइल में दिखाई नहीं देती है, इसलिए हम धन्यवाद के लिए अंतिम लाइन पर जाते हैं G, और हम एक नई लाइन बनाते हैं oजिसके साथ हम लाइन को जोड़ने के लिए लिखते हैं।

नोट 1 जिस विधि से मैंने मूल्य निर्धारित किया l:resहै वह थोड़ी भारी है और उसके जवाब में @Alex द्वारा सुझाए गए कुछ के साथ प्रतिस्थापित किया जा सकता है जैसे:

let l:res = search('export PATH=\~\/.composer\/vendor\/bin:\\\$PATH')

नोट 2 इसके अलावा फ़ंक्शन को अधिक लचीला बनाने के लिए आप तर्कों का उपयोग कर सकते हैं:

function! AddLine(line)

    let l:line =  escape(a:line, "/~$" )

    let l:res = 0
    exe "g/" . l:line . "/let l:res = l:res+1"

    if (l:res == 0)
        normal G
        exe "normal o" . a:line
    endif

endfunction
  • वर्णों के सामने escape()एक जोड़ने के लिए चाल को नोट करें \जिससे खोज में समस्या हो सकती है।
  • ध्यान दें कि आपको अभी भी \फ़ंक्शन को कॉल करते समय अपने आप से बचना होगा (मैंने \स्वचालित रूप से भागने का प्रबंधन नहीं किया है ):

    call AddLine("export PATH=~/.composer/vendor/bin:\\$PATH")
    

2

प्रयत्न:

ex ~/.bashrc -c "if search('export PATH=\~\/.composer\/vendor\/bin:\$PATH')>0 | norm quit | endif | norm Aexport PATH=~/.composer/vendor/bin:$PATH"

ध्यान दें कि एक्स-मोड के साथ -ब्लॉक ( वीमडोक देखें ) के :appendअंदर काम नहीं करेगा, इसलिए मुझे बाहर रखना होगा ।if endifnorm A...


1

मैं सामान्य रूप से उपयोग करता हूं:

perl -i -p0e '$_.="export PATH=~/bin:\$PATH\n" unless m!~/bin:!' ~/.bashrc

1

कई की उपस्थिति को सरल बनाने और बचने के लिए \, जोड़ी जाने वाली रेखा होगी export PATH=mybin:PATH

मुख्य रणनीति: "गैर- mybin" पाठ (सभी फ़ाइल) को पाठ + माइबिन-पाथ-परिभाषा के साथ प्रतिस्थापित करें :

 vim  +'s#\v%^((.|\n)(mybin:)@!)*%$#&\rexport PATH=mybin:PATH#e' -cx bashrc

या अधिक शिक्षाप्रद इंडेंटेशन के साथ :

s#                                    substitute
   \v                                  very magical to redude \

   %^                                  file begin
   ((.|\n)(mybin:)@!)*                 multi-line str without "mybin:"
                                         (any char not followed by "mybin")*
   %$                                  end of file
 #                                    by

अगर हमारे पास एक मैच है:

  1. &का पूरा पाठ है bashrcऔर
  2. & शामिल नहीं है /mybin:/

इसलिए:

 #                                    by ...
   &                                   all file
   export PATH=mybin:PATH              and the new path
 #e                                   don't complain if patt not found

-cx                                   save and leave 

अद्यतन : अंत में, हम एक स्क्रिप्ट बना सकते हैं:

$ cat bashrcfix

#!/usr/bin/vim -s
:e ~/fakebashrc
:s#\v%^((.|\n)(mybin:)@!)*%$#&\rexport PATH=mybin:PATH#e
:x

chmod 755 और इसे स्थापित करें। उपयोग:bashrcfix


सावधान रहें: \vमोड में, =वैकल्पिक का मतलब है


1

इनमें से अधिकांश उत्तर जटिल प्रतीत होते हैं कि अच्छे पुराने शेल कमांड के बारे में कैसे:

grep composer/vender ~/.bashrc || cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:\$PATH
EOF

यह आसानी से एक बश फ़ंक्शन हो सकता है:

addBashrcPath() {
  if ! grep "$1" ~/.bashrc >/dev/null 2>&1; then
    printf 'export PATH=%s:$PATH' "$1" >> ~/.bashrc
  fi
}

addBashrcPath "~/.composer/vendor/bin"

EDIT : grep का निकास कोड महत्वपूर्ण है और इस मामले में इसका उल्टा उपयोग करने की आवश्यकता है ! grep; grep -vइस स्थिति में उम्मीद के मुताबिक बाहर नहीं निकलेंगे। धन्यवाद टिप के लिए @joeytwiddle


मुझे नहीं लगता grep -vकि आपको वह निकास कोड चाहिए जो आप चाहते हैं। लेकिन ! grepकरना चाहिए।
joeytwiddle

अगर ऐसा है तो आपको -vसिर्फ जरूरत ही नहीं है !
सुकिमा

बिल्कुल सही। आप उस सुधार को करने के लिए अपना उत्तर संपादित कर सकते हैं।
joeytwiddle

1
1. आप का उपयोग करना चाहिए -Fताकि grepनियमित रूप से अभिव्यक्ति के रूप में वर्णों की व्याख्या न करें, और 2. -qअनुप्रेषित करने के बजाय का उपयोग करें /dev/null। मेरे पहले प्रश्न पर टिप्पणी देखें ।
मुरु

अच्छे अंक। उत्सुक कितना पोर्टेबल है -qऔर -Fविकल्प? मैंने सोचा कि >/dev/nullविभिन्न प्लेटफार्मों के बीच अधिक सार्वभौमिक था (सूरज बनाम एचपी बनाम मैक ओएस एक्स बनाम उबंटू बनाम फ्रीबीएसडी बनाम ...)
सुकिमा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.