IO पुनर्निर्देशन और प्रमुख आदेश


9

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

लेकिन जब मैंने आउटपुट को रीडायरेक्ट करने और फ़ाइल का उपयोग करके फिर से लिखने की कोशिश की head -1 .hgignore > .hgignore, तो फ़ाइल खाली थी। ऐसा क्यों होता है? अगर मैं इसके बजाय, कोशिश कर रहा हूँ head -1 .hgignore >> .hgignore, यह सही ढंग से जोड़ता है लेकिन यह स्पष्ट रूप से वांछित परिणाम नहीं है। इस मामले में एक अप्रकट पुनर्निर्देशन काम क्यों नहीं करता है?


जवाबों:


10

जब शेल को एक कमांड लाइन मिलती है जैसे: command > file.outशेल अपने आप खुलने वाली फ़ाइल को खोलता है (और शायद बनाता है) file.out। शेल फ़ाइल डिस्क्रिप्टर 0 को फ़ाइल फ़ाइल डिस्क्रिप्टर पर सेट करता है जो इसे खुले में मिला है। यह है कि I / O पुनर्निर्देशन कैसे काम करता है: हर प्रक्रिया फ़ाइल डिस्क्रिप्टर 0, 1 और 2 के बारे में जानती है।

इसके बारे में कठिन हिस्सा यह है कि कैसे खोलें file.out। अधिकांश समय, आप file.outऑफ़सेट 0 (यानी छंटनी) पर लिखना चाहते हैं और यही आपके लिए शेल ने किया। इसने .hignignore को छोटा कर दिया, इसे लिखने के लिए खोल दिया, फाइल करने वाले को 0 पर, फिर निष्पादित किया head। झटपट फाइल क्लॉबरिंग।

बैश शेल में, आप set noclobberइस व्यवहार को बदलने के लिए करते हैं।


आह मैंने देखा। मुझे लगता है कि शेल कमांड को चलाने से पहले फ़ाइल को काट रहा था, लेकिन मुझे पता नहीं था कि क्यों। स्पष्टीकरण के लिए धन्यवाद!
२०:

10

मुझे लगता है कि ब्रूस जवाब देता है कि शेल पाइपलाइन के साथ यहां क्या हो रहा है

मेरी पसंदीदा छोटी उपयोगिताओं में spongeसे एक है Moreutils से कमांड । लक्ष्य आउटपुट फ़ाइल को खोलने और डेटा लिखने से पहले यह सभी उपलब्ध इनपुट को "भिगोने" द्वारा इस समस्या को हल करता है। यह आपको पाइपलाइनों को लिखने की अनुमति देता है कि आप किस तरह से उम्मीद करते हैं:

$ head -1 .hgignore | sponge .hgignore

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

$ head -1 .hgingore > .hgignore.tmp
$ mv .hgignore{.tmp,}

कुछ साल बाद इसे देखते हुए, मेरे लिए एक विचार आया: क्या हम बस नहीं कर सकते head -1 .hgignore | tee .hgignore? teeकोरुटिल्स में है, और एक पर्क / साइड-इफ़ेक्ट के रूप में, यह STDOUT को भी लिखता है
voithos

@voithos मेरे ज्ञान को teeखोलता है और जब यह सब कुछ ठीक होता है, तो इसे तुरंत लिखने पर उस फ़ाइल को काट दिया जाता है, ताकि यह लिखने से पहले फ़ाइल की सामग्री को पढ़ने से पहले फ़ाइल सामग्री को पढ़ने पर दौड़ की स्थिति के मुख्य मुद्दे को हल न करें।
कालेब

आप एक ऐसा बिंदु लाते हैं, जिसके बारे में मुझे वास्तव में जानकारी नहीं थी - अर्थात्, पाइप्ड कमांड्स क्रमिक रूप से बजाय तुरंत शुरू हो जाते हैं । क्या यह सही है? मैं था, हालांकि, इसे बाहर का परीक्षण करने और tee लगता वांछित बात करने के लिए। मुझे 8.13अपनी मशीन पर संस्करण मिला है ।
वॉयथोस

1
@voithos हां एक पाइपलाइन में कमांड करता है और इसमें शामिल सभी इनपुट / आउटपुट चैनल रिवर्स ऑर्डर में शुरू होते हैं इसलिए पाइप लाइन डेटा प्राप्त करने के लिए तैयार होती है जब पहले वाला इसे देना शुरू करता है। मुझे संदेह है कि आपके परीक्षण में त्रुटिपूर्ण है क्योंकि आपने संभवतः बहुत छोटा डेटा इस्तेमाल किया है और इसे ज़रूरत पड़ने से पहले पूरी चीज़ को रीड बफर में कैश किया गया है। teeकार्यक्रम अपनी फ़ाइलें काटना होगा, यह उन्हें बफर दोगुना करने के लिए सेटअप नहीं है।
कालेब

3

में

head -n 1 file > file

fileheadशुरू होने से पहले छोटा किया जाता है, लेकिन अगर आप इसे लिखते हैं:

head -n 1 file 1<> file

यह वैसा नहीं है जैसा fileकि रीड-राइट मोड में खोला जाता है। हालाँकि, जब headलेखन समाप्त हो जाता है, तो यह फ़ाइल को छोटा नहीं करता है, इसलिए ऊपर की पंक्ति एक नो-ऑप headहोगी ( केवल अपने ऊपर पहली पंक्ति को फिर से लिखेगी और अन्य को अछूता छोड़ देगी)।

हालाँकि, के बाद headवापस आ गया है और जबकि fdअभी भी खुला है, आप एक और कमांड कॉल कर सकते हैं जो करता है truncate

उदाहरण के लिए:

{ head -n 1 file; perl -e 'truncate STDOUT, tell STDOUT'; } 1<> file

यहाँ क्या मायने रखती है वह यह है कि truncateइसके बाद के संस्करण, headबस सिर्फ पहली पंक्ति के बाद एफडी 1 फाइल के अंदर के लिए कर्सर ले जाता है। यह पहली पंक्ति को फिर से लिखता है जिसकी हमें आवश्यकता नहीं थी, लेकिन यह हानिकारक नहीं है।

POSIX हेड के साथ, हम वास्तव में उस पहली पंक्ति को दोबारा लिखे बिना दूर हो सकते हैं:

{ head -n 1 > /dev/null
  perl -e 'truncate STDIN, tell STDIN'
} <> file

यहां, हम उस तथ्य का उपयोग कर रहे हैं headजो कर्सर को उसके स्टड में ले जाता है। जबकि headआम तौर पर प्रदर्शन में सुधार करने बड़ा हिस्सा द्वारा अपने इनपुट पढ़ता था, POSIX के लिए यह (जहां संभव हो) की आवश्यकता होगी seekसिर्फ पहली पंक्ति के बाद वापस अगर यह यह परे चला गया था। ध्यान दें कि सभी कार्यान्वयन इसे नहीं करते हैं।

वैकल्पिक रूप से, आप readइस मामले में शेल के कमांड का उपयोग कर सकते हैं :

{ read -r dummy; perl -e 'truncate STDIN, tell STDIN'; } <> file

1
स्टीफन, क्या आप एक मानक या कोरुटिल कमांड के बारे में जानते हैं, STDINजो आपके द्वारा perlऊपर उपयोग किए गए कार्य के समान छोटा हो सकता है
iruvar

2
@ 1_CR, नहीं। हालांकि फ़ाइल में ddकिसी भी मनमाने ढंग से निरपेक्ष ऑफसेट से कम कर सकते हैं । तो आप दूसरी पंक्ति की बाइट ऑफ़सेट निर्धारित कर सकते हैं और वहाँ से अलग कर सकते हैंdd bs=1 seek="$offset" of=file
स्टीफन चेज़लस

1

रियल मैन का समाधान है

ed .hgignore
$d
wq

या एक लाइनर के रूप में

printf '%s\n' '$d' 'wq' | ed .hgignore

या GNU sed के साथ:

sed -i '$d' .hgignore

(नहीं, मैं मजाक कर रहा हूं। मैं एक इंटरैक्टिव संपादक का उपयोग करूंगा। vi .hgignore GddZZ)


मैंने सोचा गया है, वहाँ किसी भी लाभ का उपयोग कर रहा है :wqखत्म हो गया ZZ?
वॉइसथोस

इसके अलावा, :xजो मेरी उंगलियां स्वचालित रूप से करती हैं
ग्लेन जैकमैन

और ZQउसी के समान है:q!
ग्लेन जैकमैन

ZZ और: x केवल तभी लिखें जब लिखने के लिए कुछ हो ...: w हमेशा फ़ाइल को डिस्क पर fsyncs करता है, भले ही इसकी आवश्यकता हो। मैं उपयोग करता हूं: xa क्योंकि मैं टैब का उपयोग करता हूं।
xenoterracide

1

आप पूर्व मोड में विम का उपयोग कर सकते हैं:

ex -sc '2,d|x' .hgignore
  1. 2, अंत तक 2 लाइनों का चयन करें

  2. d हटाना

  3. x सहेजें और बंद करें


0

इन-प्लेस फ़ाइल एडिटिंग के लिए आप ओपन फाइल हैंडल ट्रिक का भी उपयोग कर सकते हैं जैसा कि Jürgen Hötzel द्वारा Redirect output में sed 's / c / d /' myFile से myFile तक दिखाया गया है ।

exec 3<.hgignore
rm .hgignore  # prevent open file from being truncated
head -1 <&3 > .hgignore

ls -l .hgignore  # note that permissions may have changed

2
और बस rm .hgignoreआपकी शक्ति के विफल होने के बाद , घंटों की मेहनत छीन ली जाती है। ठीक है, इसके लिए कोई फर्क नहीं पड़ता .hgignore, लेकिन आप ऐसा कुछ भी क्यों करेंगे जो वैसे भी जटिल है? इस प्रकार मेरा पतन: तकनीकी रूप से सही लेकिन एक बहुत बुरा विचार।
गिल्स एसओ- बुराई को रोकना '

@ गिल्स, शायद इतना अच्छा विचार नहीं है, लेकिन यह उदाहरण के लिए perl -i(inplace एडिटिंग के लिए) क्या करता है, और मुझे आश्चर्य नहीं होगा अगर कुछ कार्यान्वयनों sed -iने इसे भी किया (हालांकि GNU का नवीनतम संस्करण sedऐसा नहीं लगता)।
स्टीफन चेजलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.