xargs और vi - "इनपुट एक टर्मिनल से नहीं है"


14

मेरे पास php.iniअपने सिस्टम पर लगभग 10 फाइलें हैं, जो सभी जगह स्थित हैं, और मैं जल्दी से उनके माध्यम से ब्राउज़ करना चाहता था। मैंने इस आदेश की कोशिश की:

locate php.ini | xargs vi

लेकिन viमुझे चेतावनी देता है Input is not from a terminalऔर फिर कंसोल वास्तव में अजीब होने लगता है - जिसके बाद मुझे :q!छोड़ने के लिए प्रेस करने की आवश्यकता होती है viऔर फिर ssh सत्र से डिस्कनेक्ट करें और कंसोल को फिर से सामान्य रूप से व्यवहार करने के लिए फिर से कनेक्ट करें।

मुझे लगता है कि मुझे समझ में आ रहा है कि यहाँ क्या हो रहा है - मूल रूप से कमांड तब समाप्त नहीं हुआ है जब viशुरू किया गया है इसलिए कमांड शायद समाप्त नहीं हुआ है और viयह नहीं सोचता है कि टर्मिनल सामान्य मोड में है।

मुझे नहीं पता कि इसे कैसे ठीक किया जाए। मैंने Google को खोजा है और खराब किस्मत वाले unix.stackexchange.com को भी खोजा है।



एक साइड नोट के रूप में, आप resetअपने टर्मिनल को रीसेट करने के लिए चला सकते हैं जब यह खराब हो जाता है (आपको ssh सत्र से डिस्कनेक्ट करने की आवश्यकता नहीं है)।
बुद्धिशाल नवमी

जवाबों:


12
vi $(locate php.ini)

नोट: यदि आपके फ़ाइल पथ में स्थान हैं, तो यह समस्याएँ होंगी, लेकिन यह कार्यात्मक रूप से आपकी कमांड के समतुल्य है।
यह अगला संस्करण रिक्त स्थान को ठीक से संभालेगा लेकिन थोड़ा और अधिक जटिल है (फ़ाइल नामों में नए सिरे अभी भी इसे तोड़ देंगे हालांकि)

(IFS=$'\n'; vi $(locate php.ini))


स्पष्टीकरण:

क्या हो रहा है कि प्रोग्राम उनकी फ़ाइल डिस्क्रिप्टर को उस प्रक्रिया से विरासत में मिला है जो उन्हें पैदा करती है। xargsइसका STDIN STDOUT से जुड़ा है locate, इसलिए viइसका कोई सुराग नहीं है कि वास्तव में मूल STDIN क्या है।


2
xargs अद्भुत है, मेरे पसंदीदा उपकरणों में से एक है - यह सिर्फ उन कार्यक्रमों के साथ उपयोग करने के लिए उपयुक्त नहीं है जो डेटा फीड के अलावा किसी अन्य चीज के लिए स्टैडिन का उपयोग करते हैं। मुझे आपका उत्तर और इसके अलावा आपकी व्याख्या पसंद है, इसलिए +1 वैसे भी :)
केस

@CraigSanders मुझे यह पसंद नहीं है क्योंकि यह दुरुपयोग (अनुचित तरीके से उपयोग करना) और अंत तक तोड़ने के लिए बहुत आसान है। मैंने कभी भी किसी भी चीज़ में भाग नहीं लिया है, जिसका मुझे पूरी तरह से उपयोग xargsकरना है जो सीधे शेल (या find) के साथ नहीं किया जा सकता है । हालांकि मैं उन मामलों के बारे में सोच सकता हूं जहां यह सबसे अच्छा समाधान होगा। इसलिए, जब तक आप समझते हैं कि xargsयह क्या कर रहा है, यह कैसे तर्कों को विभाजित करता है, यह कैसे कार्यक्रम चलाता है, आदि, और इसे ठीक से उपयोग कर रहे हैं, मैं कहूंगा कि इसके लिए जाना चाहिए :-P
पैट्रिक

इसे ऐसी चीज़ों के लिए नहीं हराया जा सकता है जैसे ... | awk '{print $3}' | xargs | sed -e 's/ /+/g' | bc(फ़ील्ड 3 के सभी मूल्यों को जोड़ने के लिए)। या sed -e 's/ /|/g'एक regexp के निर्माण के साथ । और हाँ, किसी भी उपकरण की तरह, आपको यह जानने की ज़रूरत है कि इसका उपयोग कैसे करना है और इसकी सीमाएं और चेतावनी क्या हैं।
कैस

vi $(...)दृष्टिकोण भी अन्य की तुलना में गोले में वाइल्डकार्ड के साथ एक समस्या है zsh
स्टीफन चेज़लस

यह भी ध्यान दें कि xargsव्हाट्सएप मुद्दे के साथ दृष्टिकोण के साथ, सिंगल कोट्स, डबल कोट्स और बैकस्लैश के साथ फ़ाइल नाम भी एक समस्या है।
स्टीफन चेज़लस

10

यह सवाल पहले सुपर यूजर फोरम पर पूछा जा चुका है ।

उस सवाल पर @ ग्रेविटी के जवाब से उद्धरण:

जब आप xargs के माध्यम से किसी प्रोग्राम को आमंत्रित करते हैं, तो प्रोग्राम का स्टड (मानक इनपुट) / dev / null को इंगित करता है। (चूंकि xargs को मूल स्टड नहीं पता है, यह अगली सबसे अच्छी बात करता है।)

विम को अपने स्टैनिन को अपने नियंत्रण टर्मिनल के समान होने की उम्मीद है, और सीधे स्टड पर विभिन्न टर्मिनल-संबंधित ioctl का प्रदर्शन करता है। जब / dev / null (या किसी भी गैर-ट्टी फ़ाइल डिस्क्रिप्टर) पर किया जाता है, तो उन ioctls अर्थहीन होते हैं और ENOTTY को वापस कर देते हैं, जो चुपचाप अनदेखा हो जाता है।

ज़र्ग के लिए मैन्युअल पृष्ठों में इसका उल्लेख किया गया है। OSX / BSD से:

-इस आदेश को निष्पादित करने से पहले बच्चे की प्रक्रिया में / देव / tty के रूप में फिर से खोलें। यह उपयोगी है यदि आप xargs को एक इंटरैक्टिव अनुप्रयोग चलाना चाहते हैं।

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

find . -name "php.ini" | xargs -o vim

हालांकि, जीएनयू संस्करण पर कोई सीधा स्विच नहीं है, यह कमांड काम करेगा। ( dummyस्ट्रिंग को शामिल करना सुनिश्चित करें , अन्यथा यह पहली फ़ाइल को छोड़ देगा।)

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy

उपरोक्त समाधान SuperUser पर सौजन्य Jaime McGuigan हैं । इस त्रुटि के लिए साइट खोज रहे किसी भी भविष्य के आगंतुकों के लिए उन्हें यहां जोड़ना।


3
-O टिप के लिए +1 धन्यवाद। मैं वर्षों से xargs का उपयोग कर रहा हूं और कभी भी इस पर ध्यान नहीं दिया गया कि .... मेरे सिस्टम पर मैन पेज की जाँच की, ऐसा इसलिए है क्योंकि यह GNU xargs सुविधा नहीं है। मैन पेज यह प्रदान xargs sh -c 'emacs "$@" < /dev/tty' emacsकरता है कि वे जो दावा करते हैं वह अधिक लचीला और पोर्टेबल विकल्प है (हालांकि यह GNU के लिए एक तरह से मज़ेदार है कि सुविधाओं के लिए पोर्टेबिलिटी को प्राथमिकता दी जाए :)।
कैस

2

GNU के साथ findutils, और प्रक्रिया प्रतिस्थापन (ksh, zsh, bash) के समर्थन के साथ एक शेल, आप कर सकते हैं:

xargs -r0a <(locate -0 php.ini) vi

-a filenameस्टड के बजाय फ़ाइल सूची को पास करने का विचार । -0यह सुनिश्चित करना कि यह फ़ाइल के नाम वाले वर्णों या गैर-वर्णों की परवाह किए बिना काम करता है।

के साथ zsh, आप कर सकते हैं:

vi ${(0)"$(locate -0 php.ini)"}

(कहां 0NULs पर विभाजित करने के लिए पैरामीटर विस्तार ध्वज है)।

हालांकि ध्यान दें कि अगर कोई फ़ाइल नहीं मिली है, तो इसके विपरीत xargs -rअभी भी viतर्क के बिना चलता है।


0

एक ही संपादक के भीतर कई php.ini संपादित करें?

प्रयत्न: vim -o $(locate php.ini)


0

यह त्रुटि तब होती है जब विम को आमंत्रित किया जाता है और यह टर्मिनल के बजाय पिछले पाइपलाइन के आउटपुट से जुड़ा होता है और इसे अलग-अलग अनपेक्षित इनपुट (जैसे NULs) प्राप्त हो रहे हैं। जब आप दौड़ते हैं तो वही होता है: vim < /dev/nullइसलिए resetइस मामले में कमांड मदद करता है। यह सुपरसुसर में गुरुत्वाकर्षण द्वारा अच्छी तरह से समझाया गया है ।

यूनिक्स / ओएसएक्स पर आप पैरामीटर के xargsसाथ उपयोग कर सकते हैं -o, जैसे:

locate php.ini | xargs -o vim

-oआदेश को निष्पादित करने से पहले बच्चे की प्रक्रिया में / देव / tty के रूप में फिर से खोलें। यह उपयोगी है यदि आप xargs को एक इंटरैक्टिव अनुप्रयोग चलाना चाहते हैं।

लिनक्स पर निम्न वर्कअराउंड आज़माएँ:

locate php.ini | xargs -J% sh -c 'vim < /dev/tty $@'

वैकल्पिक रूप से बल आवंटन के parallelबजाय GNU का उपयोग करें xargs, उदाहरण के लिए:

locate php.ini | parallel -X --tty vi

नोट: parallelयूनिक्स / OSX पर काम नहीं करेगा क्योंकि इसमें अलग-अलग पैरामीटर हैं और यह tty का समर्थन नहीं करता है।

कई अन्य लोकप्रिय आदेशों के रूप में अच्छी तरह से (जैसे छद्म tty आवंटन प्रदान करता है -tमें ssh), इसलिए मदद के लिए जाँच करें।

वैकल्पिक रूप findसे संपादित करने के लिए फ़ाइल नामों को पास करने के लिए उपयोग करें, इसलिए उदाहरण के लिए xargs, बस उपयोग की आवश्यकता नहीं है -exec:

find /etc -name php.ini -exec vim {} +

0

@ पैट्रिक की IFSहैक केवल गूंगे गोले की तरह bashऔर के लिए आवश्यक है zshfish डिफ़ॉल्ट रूप से स्ट्रिंग को नईलाइन्स पर विभाजित करता है।

$ vim (locate php.ini)

और भगवान हम सभी की मदद करते हैं अगर हममें से किसी एक के पास वास्तव में उसके नाम की एक नई लाइन है। लिनक्स का उपयोग करने के 17 साल बाद, मैंने इसे एक बार भी नहीं देखा है। मैं केवल उन स्क्रिप्ट्स के लिए नए नाम के साथ फिल्म्स का समर्थन करने की जहमत उठाता हूं, जिन्हें किसी भी तरह से काम नहीं करना है, लेकिन स्क्रिप्ट ऐसी हैं जो शायद अंतःक्रियात्मक रूप से नहीं चल रही हैं।


zshडिफ़ॉल्ट रूप से SPC, TAB, NL और NUL पर विभाजन। जिस चीज की तुलना में यह नहीं करता bashहै वह परिणाम पर ग्लोबिंग करता है इसलिए फ़ाइल नामों में वाइल्डकार्ड वर्ण समस्या नहीं हैं। में zsh, आप एक स्पष्ट विभाजन ऑपरेटर के लिए IFS=$'\0'; vi $(locate -0 php.ini)मेरे उत्तर में या जैसा कि मैंने दिखाया था vi ${(0)"$(locate -0 php.ini)"}। इसके अलावा tcshvi "`locate php.ini`"
Stéphane Chazelas

जाग, बकवास ठीक है यह काम करता है: $ f='not there'<ret>$ ls $f<ret>लेकिन यह नहीं है: ls echo not there। ठीक है ऐसा लगता है कि मुझे इसे थोड़ा अपडेट करने की आवश्यकता है।
enigmaticPhysicist

हाँ, जब आप करते हैं तो zsh सही काम नहीं करता है ls "$(echo test; echo other test)"। केवल मछली ही सही काम करती है।
enigmaticPhysicist

आप उद्धरण के बिना एक ही मतलब है, यह "सही" नहीं है, कि लाइनों पर बंटवारे है, यह सिर्फ एक अलग पसंद है। zsh डिफ़ॉल्ट रूप से (अन्य सभी गोले की तरह) शब्दों पर विभाजित होता है और इसे $IFSस्पष्ट ऑपरेटरों ( fया 0पैरामीटर विस्तार झंडे) के माध्यम से या NULs पर या तो लाइनों या विभाजन पर विभाजित करने के लिए कहा जा सकता है । मनमाने फ़ाइल नामों के लिए, शब्द से विभाजित करना या लाइन से विभाजित करना समान रूप से गलत है , आपको एनयूएल पर विभाजित करने या कुछ एन्कोडिंग को पार्स करने की आवश्यकता है, जो fishनहीं कर सकते। में zsh, वह है IFS=$'\0'; ls -ld -- $(printf '%s\0' "$file1" "$file2")याls -ld -- ${(0)"$(printf '%s\0' "$file1" "$file2")"}
स्टीफन चेज़लस

भावहीन। न्यूलाइन्स पर बंटवारा काफी अच्छा है। जैसा कि जवाब में कहा गया है, फ़ाइल नाम में नई कहानियाँ अत्यंत दुर्लभ हैं। मैंने 17 सालों में ऐसा कभी नहीं देखा है। और न्यूलाइन्स, नैल्स की तुलना में अधिक सुविधाजनक विभाजक हैं।
enigmaticPhysicist

0

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

उदाहरण के लिए

vi `find / -type f -name 'php.ini'`

बैक-टिक्स के भीतर निहित कमांड पहले निष्पादित करेगा। निहित कमांड का आउटपुट तब बैक-टिक्स से पहले बताई गई कमांड द्वारा निष्पादित किया जाता है।

उदाहरण के लिए, ऊपर की पंक्ति में, find / -type f -name 'php.ini'कमांड पहले निष्पादित करेगा, आउटपुट भेजेगा, और फिर viउस आउटपुट पर लागू विभाजन + ग्लोब के परिणाम पर निष्पादित किया जाएगा।


3
सिंगल-कोट्स के लिए बैक-टिक्स बहुत आसानी से भ्रमित होते हैं। $(find ...)इसके बजाय उपयोग करें ।
कैस

1
यह अनुमान लगाने से फ़ाइल नामों में रिक्त स्थान और / या नईलाइन्स पर भी विराम लग जाएगा?
cwd

इस प्रकार आप bash scripting में शेल कमांड निष्पादित करते हैं। मैंने अपनी लिपियों में या एक लाइनर में इसका उपयोग करते समय कभी भी रिक्त स्थान या नई लाइनों पर कुछ भी तोड़ नहीं दिया है। हालाँकि, मैंने viइस पद्धति का उपयोग करके कई फ़ाइलों को खोलने की कोशिश नहीं की है । यह बहुत संभव है कि यह नई लाइनों या रिक्त स्थान पर टूट सकता है, यह इस बात पर निर्भर करता है कि viआउटपुट कैसे पढ़ रहा है और कैसे निष्पादित कर रहा है।
tacotuesday
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.