खोज के माध्यम से vi आमंत्रित करना | xargs मेरा टर्मिनल तोड़ता है। क्यों?


137

जब इस तरह के vimमाध्यम से आह्वान find | xargs:

find . -name "*.txt" | xargs vim

आपको एक चेतावनी मिलती है

Input is not from a terminal

और बाद में बहुत टूटे हुए व्यवहार के साथ एक टर्मिनल। ऐसा क्यों है?


11
साइड नोट: आप इस ऑपरेशन को पूरी तरह से vim के भीतर कर सकते हैं, उपयोग findया xargsबिल्कुल नहीं। बिना तर्कों के साथ खुली विम, फिर :args **/*.txt<CR>संपादक के अंदर से विम के तर्क सेट करने के लिए चलाएँ ।
ट्रेवर पॉवेल

3
@TrevorPowell: इन सभी वर्षों में, विम ने मुझे विस्मित करना बंद नहीं किया।
देवसोलर



जवाबों:


100

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

$ सच | xargs filan -s
    ० चर्देव / देव / नल
    1 tty / dev / pts / 1
    2 tty / dev / pts / 1

$ सच | xargs ls -l / dev / fd /

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

  • अधिक विशिष्ट कारण पर मेरा अनुमान: स्टार्टअप पर विम पुरानी टर्मिनल सेटिंग्स को पढ़ता है और याद करता है, और बाहर निकलते समय उन्हें पुनर्स्थापित करता है। हमारी स्थिति में, जब "पुरानी सेटिंग्स" को एक गैर-टीडी fd (फ़ाइल डिस्क्रिप्टर) के लिए अनुरोध किया जाता है, तो विम सभी मानों को खाली और सभी विकल्पों को अक्षम करता है, और लापरवाही से आपके टर्मिनल पर सेट करता है।

    आप इसे रनिंग से देख सकते हैं vim < /dev/null, इसे बाहर निकाल सकते हैं, फिर रनिंग sttyकरेंगे, जो कि बहुत सारे आउटपुट देगा <undef>। लिनक्स पर, रनिंग stty saneटर्मिनल को फिर से उपयोग करने योग्य बना देगा (हालांकि इसमें ऐसे विकल्प खो जाएंगे जैसे कि iutf8संभवतः बाद में छोटी-मोटी झुंझलाहट हो सकती है)।

आप विम में इस बग पर विचार कर सकते हैं , क्योंकि यह /dev/ttyटर्मिनल नियंत्रण के लिए खोल सकता है , लेकिन नहीं। (स्टार्टअप के दौरान कुछ बिंदु पर, विम अपने स्टनर को डुप्लिकेट करता है, जो इसे आपके इनपुट कमांड्स को पढ़ने की अनुमति देता है - लेखन के लिए खोले गए एक fd से - लेकिन यहां तक ​​कि इसे जल्दी पूरा नहीं किया जाता है।)


20
+1, और टीएल के लिए; डीआर लोग बस चलाते हैंstty sane
doc_id

@rahmanisback: अन्य उत्तर, प्लस ट्रेवर की टिप्पणी, सभी ने पहले स्थान पर टर्मिनल टूटने से बचने के तरीके प्रदान किए। मैंने ग्रेविटी के उत्तर को स्वीकार कर लिया, क्योंकि मेरा प्रश्न "क्यों" था, "कैसे न बचें" - यह एक और प्रश्न से आच्छादित है जो वास्तव में इस एक को जन्म देता है
DevSolar

@DevSolar अंडरस्टूड, लेकिन मेरे जैसे कुंठित लोगों के बारे में सोचें, जो सिर्फ गूगल करते हैं कि कैसे उस व्यवहार से छुटकारा पाएं, जबकि दुर्भाग्य से - अभी पर्याप्त समय नहीं है "क्यों" का अध्ययन करने के लिए, जो फिर भी बहुत दिलचस्प है।
doc_id

4
जब मेरा टर्मिनल टूटता है, तो इस तरह, मैं resetइसके बजाय का उपयोग stty saneकरता हूं और यह उसके बाद ठीक काम करता है।
कैपि इथरियल

136

(ग्रेविटी की व्याख्या के बाद, यह xargsइंगित stdinकरता है /dev/null)

समाधान इस समस्या के लिए जोड़ने के लिए है -oकरने के लिए पैरामीटर xargs। से man xargs:

-o

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

इस प्रकार, कोड की निम्न पंक्ति आपके लिए काम करना चाहिए:

खोजो। -name "* .txt" | xargs -o vim

GNU xargs 2017 में कुछ रिलीज़ (लंबे विकल्प नाम के साथ --open-tty) के बाद से इस एक्सटेंशन का समर्थन करता है ।

पुराने या अन्य संस्करणों के लिए, आप /dev/ttyसमस्या को हल करने के लिए स्पष्ट रूप से पास हो सकते हैं :

find . -name "*.txt" | xargs bash -c '</dev/tty vim "$@"' ignoreme

( ignoremeवहाँ $ 0 लेने के लिए है, ताकि $ @ xargs से सभी तर्क हैं।)


2
आप इसमें से एक बैश उर्फ ​​कैसे बनाएंगे? $@लगता नहीं कि तर्कों का सही अनुवाद किया जा रहा है।
zanegray

1
@zanegray - आप एक उपनाम नहीं बना सकते हैं, लेकिन आप इसे एक समारोह बना सकते हैं। कोशिश करें:function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
क्रिस्टोफर

GNU xargs समाधान कैसे काम करता है, और आपको डमी ignoremeस्ट्रिंग की आवश्यकता क्यों है, इसकी विस्तृत व्याख्या के लिए , vi.stackexchange.com/a/17813
wisbucky

@zanegray, आप इसे एक उपनाम बना सकते हैं। उद्धरण बहुत मुश्किल हैं। Vi.stackexchange.com/a/17813
बुद्धिमानबीच

The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.(यह मेरे लिए macOS पर उपलब्ध नहीं था क्योंकि मैंने होमब्रेव (GNU एक) से xargs स्थापित किया था
लोकलहोस्टेडदेव

33

सबसे आसान तरीका:

vim $(find . -name "*foo*")

5
मुख्य प्रश्न "क्यों" था, न कि "इससे कैसे बचा जाए", और यह ढाई साल पहले संतोष का जवाब दिया गया है।
देवसोलर

5
यह निश्चित रूप से, ठीक से काम नहीं करता है जब फ़ाइलनाम में रिक्त स्थान या अन्य विशेष वर्ण होते हैं, और यह एक सुरक्षा जोखिम भी है।
देजय क्लेटन

1
मेरा पसंदीदा उत्तर क्योंकि यह हर उस कमांड के लिए काम करता है जो फाइलों को सूचीबद्ध करता है, न कि केवल "खोज" या वाइल्डकार्ड। यह एक छोटे से विश्वास की आवश्यकता है, जैसा कि देजय बताते हैं।
ट्रैविस विल्सन

1
यह कई उपयोग मामलों के साथ काम नहीं करेगा xargs के लिए डिज़ाइन किया गया है: उदाहरण के लिए, जब रास्तों की संख्या बहुत अधिक है (cc @TravisWilson)
अच्छा व्यक्ति

21

यह ठीक काम करना चाहिए अगर आप xargs में पाइपिंग के बजाय खोज पर -exec विकल्प का उपयोग करते हैं।

find . -type f -name filename.txt -exec vi {} + 

2
हुह ... चाल है +(के बजाय "हमेशा की तरह" \;) में सभी पाया फ़ाइलें प्राप्त करने से एक एक विकल्प मैं - विम सत्र रखने के बारे में भूल जाते हैं। आप निश्चित रूप से, और उसके लिए +1 सही हैं। मैं vim $(find ...)बस आदत से बाहर का उपयोग करें । हालांकि, मैं वास्तव में पूछ रहा था कि पाइप ऑपरेशन ने टर्मिनल पर शिकंजा क्यों डाला, और ग्रेविटी ने उसके स्पष्टीकरण के साथ इसे पकड़ लिया।
DevSolar

2
यह सबसे अच्छा उत्तर है और यह BSD / OSX / GNU / Linux दोनों पर काम करता है।
केविनरपे

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

8

इसके बजाय GNU समानांतर का उपयोग करें:

find . -name "*.txt" | parallel -j1 --tty vim

या यदि आप सभी फाइलों को एक बार में खोलना चाहते हैं:

find . -name "*.txt" | parallel -Xj1 --tty vim

यह भी फ़ाइल नाम के साथ सही ढंग से संबंधित है:

My brother's 12" records.txt

अधिक जानने के लिए इंट्रो वीडियो देखें: http://www.youtube.com/watch?v=OpaiGYxkSuQ


1
सर्वव्यापी उपलब्ध नहीं है। अधिकांश दिन मैं उन सर्वरों पर काम कर रहा हूं जहां मैं अतिरिक्त उपकरण स्थापित करने के लिए स्वतंत्रता में नहीं हूं। लेकिन वैसे भी संकेत के लिए धन्यवाद।
१०:१६ पर देवसोलर

यदि आपकी 'बिल्ली> फ़ाइल करने की स्वतंत्रता है; chmod + x फ़ाइल 'तो आप GNU समानांतर स्थापित कर सकते हैं: यह बस एक पर्ल स्क्रिप्ट है। यदि आप मैन पेज और ऐसा चाहते हैं, तो आप इसे अपने होमडायर के नीचे स्थापित कर सकते हैं: ./configure --prefix = $ HOME && मेक && मेक इनस्टॉल
Ole Tange

2
ठीक है, कि कोशिश की - लेकिन समानांतर सभी फ़ाइलों को नहीं खोलता है, यह उन्हें उत्तराधिकार में खोलता है । यह एक साधारण ऑपरेशन के लिए काफी मुफीद है। vim $(find . -name "*.txt")सरल है, और आप एक ही बार में सभी फ़ाइलों को खोलते हैं।
DevSolar

5
@DevSolar: कुछ हद तक असंबंधित, लेकिन दोनों find | xargsऔर $(find)फ़ाइल नामों में रिक्तियों के साथ बड़ी समस्याओं होगा।
ग्रैविटी

2
@grawity Correct, लेकिन इसके आस-पास कोई आसान तरीका नहीं है (कि मुझे पता है)। आप के साथ fiddling शुरू करने के लिए होगा $IFS, -print0और सामान, और फिर आप एक शॉट कमांड लाइन समाधान के दायरे को छोड़ दिया और एक बिंदु पर पहुंच गए जहां आपको एक स्क्रिप्ट के साथ आना चाहिए ... एक कारण है कि फ़ाइल नाम में स्थान हतोत्साहित होते हैं ।
देवसर

0

शायद सबसे अच्छा नहीं है, लेकिन यहाँ यह मेरे द्वारा उपयोग की जाने वाली स्क्रिप्ट (नाम vim-open) है:

#!/usr/bin/env ruby

require 'shellwords'

inputs = (ARGV + (STDIN.tty? ? [] : STDIN.to_a)).map(&:strip)
exec("</dev/tty vim #{inputs.flatten.shelljoin}")

उदाहरण के लिए vim-open a b cऔर साथ काम करेंगेls | vim-open


कई अन्य उत्तरों की तरह, ध्यान दें कि वास्तविक प्रश्न "क्यों" था, न कि "इससे कैसे बचें"। (जिसके लिए मैं अभी भी अपने प्रश्न के तहत ट्रेवर की टिप्पणी को सबसे ठोस तरीके से इंगित करूँगा जो स्क्रिप्टिंग, उपनाम या कुछ भी करने की आवश्यकता नहीं है।)
DevSolar
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.