बैश आउटपुट रीडायरेक्शन


10

के साथ समस्या मैं अंतिम पंक्ति को छोड़कर फ़ाइल की सभी पंक्तियों को हटाने की कोशिश कर रहा था लेकिन निम्न आदेश काम नहीं करता था, हालांकि file.txt खाली नहीं है।

$cat file.txt |tail -1 > file.txt 

$cat file.txt 

ऐसा क्यों है?

19

एक पाइपलाइन के माध्यम से एक फ़ाइल से रीडायरेक्ट करना एक ही फाइल में वापस असुरक्षित है; को tail से पहले पाइपलाइन के अंतिम चरण को सेट करते समय खोल से अधिलेखित किया जाता है, तो आप पहले चरण को पढ़ना शुरू कर देते हैं, तो आप खाली आउटपुट के साथ समाप्त होते हैं।

करो बजाय निम्नलिखित:

tail -1 file.txt >file.txt.new && mv file.txt.new file.txt 

... अच्छी तरह से, वास्तव में, ऐसा नहीं करते हैं कि उत्पादन कोड में; खासकर यदि आप एक सुरक्षा के प्रति संवेदनशील वातावरण में कर रहे हैं और रूट के रूप में चल रहा है, निम्नलिखित अधिक उपयुक्त है:

tempfile="$(mktemp file.txt.XXXXXX)" 
chown --reference=file.txt -- "$tempfile" 
chmod --reference=file.txt -- "$tempfile" 
tail -1 file.txt >"$tempfile" && mv -- "$tempfile" file.txt 

एक और दृष्टिकोण (अस्थायी फ़ाइलों से परहेज है, जब तक <<< परोक्ष अपने मंच पर उन्हें बनाता है) पीछा कर रहा है:

lastline="$(tail -1 file.txt)"; cat >file.txt <<<"$lastline" 

(उपर्युक्त कार्यान्वयन बैश-विशिष्ट है, लेकिन ऐसे मामलों में काम करता है जहां गूंज नहीं है - जैसे कि अंतिम पंक्ति में "--version" है, उदाहरण के लिए)।

अंत में, एक moreutils से स्पंज का उपयोग कर सकते हैं:

tail -1 file.txt | sponge file.txt 
  0

ध्यान दें कि पूंछ एक फ़ाइल नाम को तर्क के रूप में स्वीकार करता है: "tail -1 file.txt> file.txt.new && mv file.txt.new file.txt" 23 sep. 082008-09-23 19:35:56

  0

@ मार्सेल लेवी - बिल्कुल सही, और इसमें चलाने की क्षमता है उस तरह से अधिक कुशलता से; अपडेट किया गया। 23 sep. 082008-09-23 20:47:58

  0

प्रिय @ चार्ल्सडफी, मैं यह ध्यान रखना चाहता हूं कि आपके "सुरक्षित" संस्करण की आवश्यकता है कि उपयोगकर्ता ऐसा कर रहा है जो रूट होगा। यह कैसे सुरक्षित है, मैं कह सकता हूं कि "file.txt" तक पहुंच पर इसकी अनुमतियां और मालिक लागू करने के लिए पर्याप्त नहीं है। उस पर विचार करें "फाइल।txt "की अनुमति 0666 है और इसे" ~/.ssh "फ़ोल्डर के अंदर रखा गया है जिसमें 0700 की अनुमति है। इस मामले में मेरा समाधान अधिक सुरक्षित होगा क्योंकि यह उस फ़ाइल को दुनिया में प्रकट नहीं करेगा। क्या मुझे इसके कारण आपके जवाब को कम करना चाहिए ?;) 14 may. 132013-05-14 13:02:27

  0

@ चार्ल्स डफी, ओह ... मैं पूरी तरह से भूल गया हूं कि यदि कोई व्यक्ति उस फ़ाइल में एक पंक्ति जोड़ देगा तो आप डेटा खो सकते हैं क्योंकि आप इसे 'tail -1 file.txt' के पूरे समय के दौरान बेनकाब करते हैं। परिणामस्वरूप आप पुरानी सामग्री के साथ मौजूदा 'file.txt' को ओवरराइट कर सकते हैं। क्या मुझे इसके कारण आपके उत्तर को कम करना चाहिए?;) 14 may. 132013-05-14 13:15:35

  0

@ony' chown' का उपयोग संभावित रूप से उपयोगी है अगर फ़ाइल द्वितीयक समूह के स्वामित्व में है, और _not_ उस मामले में विशेषाधिकारों की आवश्यकता है। 14 may. 132013-05-14 13:18:36

  0

@ony दौड़ की स्थिति के लिए - यदि यह टालने योग्य था, तो निश्चित रूप से, इसके लिए मुझे नीचे छोड़ दें। मुझे यह सुनना अच्छा लगेगा कि यह कैसे बचाना होगा (विशेष रूप से 'sed -i' , 'ed', 'ex' और kin या तो परमाणु नहीं हैं) 14 may. 132013-05-14 13:19:43

  0

@Char lesduffy, फ़ाइल '~/.ssh/file.txt' पर अनुमतियों के अलग-अलग स्तर हैं - पहले '~' (और उसके सभी मूल फ़ोल्डर्स), फिर '.ssh' (जो आमतौर पर 0700 है) और फिर' file.txt '। आप अंतिम आइटम के लिए केवल अनुमतियों की प्रतिलिपि बनाते हैं ताकि आप संभावित रूप से सुरक्षा के स्तर को कम कर सकें। मेरे समाधान में यह एक ही फ़ाइल का उपयोग करके बचाया जाता है (बिना चलने/प्रतिलिपि/ओवरराइटिंग के)। तो यह मुद्दा टालने योग्य है - इसका मतलब है कि मैं डाउनवोट कर सकता हूं? बेशक मेरे समाधान में अन्य समस्या है - फ़ाइल का आकार इसकी सामग्री के साथ अलग हो सकता है, लेकिन यह एक अन्य मुद्दा है। मेरे मूल उत्तर में मैं अनुमतियों के साथ भी समस्या से बचता हूं। 14 may. 132013-05-14 13:33:32

  0

@ony यह एक आकर्षक समस्या है - अस्थायी फ़ाइल को अंतिम स्थान पर TEMPDIR का उपयोग करने के बजाय बनाया जाना चाहिए। उस बदलाव को बनाना; सूचक के लिए धन्यवाद। 14 may. 132013-05-14 13:38:47

  0

मुझे लगता है कि TEMPFILE = $ (tempfile) बहुत आसान है ... बेशक (मुंह में पैर) हर डिस्ट्रो में यह अभी भी नहीं है? क्यों अगर यह "सुरक्षित" है तो मुझे आश्चर्य है .. 16 jul. 142014-07-16 15:12:40

  0

@osirisgothra, वास्तव में, 'tempfile' distro-specific है। ओएस एक्स पर उपलब्ध नहीं है, जो नवीनतम आर्क लिनक्स पर उपलब्ध नहीं है, और सी। इसके अलावा, उपयोगकर्ता को सॉफ़्टवेयर को जानने में सक्षम होना चाहिए कि टेम्पलेट पैरामीटर को एक मूल्यवान सुविधा बनाने के साथ दी गई अस्थायी फ़ाइल या निर्देशिका किस प्रकार से जुड़ी हुई है। 16 jul. 142014-07-16 15:57:52


0

ऐसा लगता है कि आप इसे उसी फ़ाइल नाम पर वापस लिख रहे हैं। यदि आप निम्न कार्य करते हैं तो यह काम करता है:

$cat file.txt | tail -1 > anotherfile.txt 
  0

के लिए कोई ज़रूरत नहीं है खो जाएगा होगा अटकलें "लगता है" , और रीडायरेक्शन (इस प्रकार, ट्रंकेटिंग मोड में 'anotherfile.txt' का खुलासा) * * निष्पादन से पहले * होता है (इस मामले में,' पूंछ 'के; चाहे यह' बिल्ली 'के निष्पादन से पहले होता है, अनिश्चित है, लेकिन एक कार्यक्रम के बाद से चूंकि 'बिल्ली' को शुरू करने के लिए समय की आवश्यकता होती है, इसलिए यह बहुत अधिक संभावना है कि 'catfile.txt' का कटाव पहले से ही हो जाएगा 'बिल्ली' लोड होने से पहले और इनपुट के लिए अपना तर्क खोलने के लिए तैयार हो जाएगा)। 10 mar. 162016-03-10 19:13:22


1

लुईस Baumstark कहते हैं, यह है कि आप उसी फ़ाइल नाम के लिए लिख रहे पसंद नहीं है।

ऐसा इसलिए है क्योंकि खोल "file.txt" खुलता है और "cat file.txt" चलाने से पहले इसे पुनर्निर्देशन करने के लिए इसे छोटा करता है। तो, आप

tail -1 file.txt > file2.txt; mv file2.txt file.txt 

0

tail -1 > file.txt करने के लिए है आपकी फ़ाइल के ऊपर लिख देगा, क्योंकि पुनर्लेखन का से पहले क्या होगा आपके पाइप लाइन में आदेशों के किसी भी क्रियान्वित कर रहे हैं एक खाली फ़ाइल को पढ़ने के लिए बिल्ली के कारण।


3

'बिल्ली' निष्पादित होने से पहले, बैश ने अपनी सामग्री को साफ़ करने के लिए पहले से ही 'file.txt' खोला है।

सामान्य रूप से, उन फ़ाइलों को न लिखें जिन्हें आप उसी कथन में पढ़ रहे हैं। इसे उपरोक्त के रूप में एक अलग फ़ाइल में लिखकर चारों ओर काम किया जा सकता है:

$cat file.txt | tail -1 >anotherfile.txt 
$mv anotherfile.txt file.txt
या स्पंज जैसे moreutils:
$cat file.txt | tail -1 | sponge file.txt
यह काम करता है क्योंकि स्पंज तब तक प्रतीक्षा करता है जब तक इसकी इनपुट स्ट्रीम अपनी आउटपुट फ़ाइल खोलने से पहले समाप्त हो जाती है।

  0

क्या 'cat' आपको 'tail -1 file.txt' पर कोई मान देता है? यह निश्चित रूप से चीजें ** दूर ** कम कुशल बनाता है यदि आपका 'file.txt' बड़ा है - यदि 'पूंछ' में प्रत्यक्ष खोज योग्य फ़ाइल डिस्क्रिप्टर है, तो यह सीधे फ़ाइल के अंतिम केबी पर कूद सकता है, केवल उसे पढ़ सकता है, और पिछली पंक्ति को 1kb से बड़ा होने पर बैक अप लेने की अंतिम पंक्ति को खोजने का प्रयास करें; यदि यह सब 'बिल्ली' से एक पाइप है, तो इसे शुरुआत से फ़ाइल को पढ़ना होगा - इससे कोई फर्क नहीं पड़ता कि यह कितना बड़ा है - अंत तक पहुंचने के लिए। 21 jul. 162016-07-21 14:42:36

  0

... 'पूंछ -1 <file.txt' इसी प्रकार एक असली, तलाशने योग्य फ़ाइल डिस्क्रिप्टर और stdin पर होगा (इस प्रकार आपके वर्तमान 'cat file.txt | tail -1' दृष्टिकोण पर पारित कमांड लाइन तर्कों में समान) । 21 jul. 162016-07-21 14:43:19


2

जब आप पार्टी की योजना बनाई अपने कमांड स्ट्रिंग सबमिट करते हैं, यह निम्नलिखित है:

  1. बनाता है एक आई/ओ पाइप।
  2. पाइप से पढ़ने, और file.txt पर लिखने, "/ usr/bin/tail -1" शुरू करता है।
  3. पाइप को लिखते हुए "/ usr/bin/cat file.txt" शुरू करता है।

जब तक 'बिल्ली' पढ़ना शुरू होता है, तब तक 'file.txt' को 'पूंछ' द्वारा छोटा कर दिया गया है।

यह यूनिक्स और शैल पर्यावरण के डिजाइन का हिस्सा है, और मूल बोर्न शैल के लिए सभी तरह से वापस चला जाता है। 'एक विशेषता है, एक बग नहीं।

  0

क्या (2) और (3) के बीच ऑर्डरिंग निर्दिष्ट है? मेरी धारणा यह है कि वे एक साथ हो रहे हैं, जो प्रभावी रूप से एक दौड़ होता है - हालांकि '/ usr/bin/tail' से पहले लिखने के लिए' file.txt' खोला जाता है, जिससे छंटनी जीतने की अत्यधिक संभावना होती है दौड़ (चूंकि '/ usr/bin/cat' को एक निष्पादन की आवश्यकता होती है, जिसमें सभी लिंकर/लोडर प्रदर्शन प्रभाव का तात्पर्य है)। 21 jul. 162016-07-21 14:46:14


2

tmp = $ (tail -1 file.txt); echo $ tmp> file.txt;

+1

अस्थायी रूप से अस्थायी फ़ाइलों से बचाता है, लेकिन सभी मानक मुद्दों से बचने के लिए इसे उद्धृत किया जाना चाहिए। 23 sep. 082008-09-23 20:31:58


5

आप एसईडी सभी लाइनों को हटाने के लिए एक फ़ाइल से पिछले उपयोग कर सकते हैं लेकिन:

sed -i '$!d' file 
  • मैं जगह में फ़ाइल को बदलने के sed बताता है; अन्यथा, परिणाम STDOUT को लिखना होगा।
  • $ वह पता है जो फ़ाइल की अंतिम पंक्ति से मेल खाता है।
  • डी हटाएं आदेश है। इस मामले में, इसे से अस्वीकार कर दिया गया है!, इसलिए सभी लाइन पते से मेल नहीं खाए जाएंगे।
  0

इस बारे में एकमात्र दुर्भाग्यपूर्ण बात यह है कि 'sed -i' POSIX-compliant नहीं है लेकिन एक जीएनयू एक्सटेंशन है। जगह में संपादित करने के लिए 'ed' या' ex' का उपयोग करना उन चेतावनियों से बच जाएगा। 14 may. 132013-05-14 13:16:13


2

यह एक लिनक्स खोल में अच्छी तरह से काम करता है:

replace_with_filter() { 
    local filename="$1"; shift 
    local dd_output byte_count filter_status dd_status 
    dd_output=$("[email protected]" <"$filename" | dd conv=notrunc of="$filename" 2>&1; echo "${PIPESTATUS[@]}") 
    { read; read; read -r byte_count _; read filter_status dd_status; } <<<"$dd_output" 
    ((filter_status > 0)) && return "$filter_status" 
    ((dd_status > 0)) && return "$dd_status" 
    dd bs=1 seek="$byte_count" if=/dev/null of="$filename" 
} 

replace_with_filter file.txt tail -1 

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

फ़ाइल कॉपी विधि पर इसका लाभ निम्न हैं: 1) कोई अतिरिक्त डिस्क स्थान आवश्यक नहीं है, 2) बड़ी फ़ाइलों पर तेज़ प्रदर्शन, और 3) शुद्ध खोल (डीडी के अलावा)।

  0

मुझे यह पसंद है - यह एक अभिनव विचार है। मैं इस समय केवल इसे ऊपर नहीं उठा रहा हूं क्योंकि '$ FILTER' का उपयोग http://mywiki.wooledge.org/BashFAQ/050 से गुजरता है (स्ट्रिंग-स्प्लिटिंग पर भरोसा करने के लिए सही ढंग से कमांड बनाने के लिए अत्यंत त्रुटि-प्रवण है)। 13 may. 132013-05-13 14:14:29

  0

मुझे आशा है कि आप मेरे भारी हाथों के संपादन को ध्यान में रखें; यह समाधान अब काफी मजबूत होना चाहिए। 14 may. 132013-05-14 13:14:09

  0

मैं इसे 'replace_with_filter' नहीं कहूंगा। यह केवल फ़िल्टर के लिए काम करेगा कि प्रत्येक अगले खंड के साथ डेटा मूल खंड से अधिक नहीं होता है। अन्यथा फ़िल्टर द्वारा पढ़ी गई जानकारी को इसके आउटपुट द्वारा ओवरराइट किया जा सकता है। ध्यान दें कि पिछले 'dd' के बजाय आप 'truncate -s $ byte_count" $ filename "' का उपयोग कर सकते हैं। 14 may. 132013-05-14 16:00:28

  0

@ony 'truncate' एक पॉज़िक्स-मानक उपकरण नहीं है - यह आधुनिक कोरुटिल्स में पाया जाता है, लेकिन वहां कई प्लेटफ़ॉर्म हैं जहां बैश उपलब्ध हैं लेकिन यह नहीं है। 14 may. 132013-05-14 17:23:21


1

बस इस मामले के लिए

cat < file.txt | (rm file.txt; tail -1 > file.txt)
का उपयोग करना संभव है जो "बिल्ली" कनेक्शन को "(...)" में सबहेल के साथ "file" कनेक्शन से पहले "file.txt" खोल देगा। "आरएम file.txt" डिस्क से संदर्भ को हटा देगा इससे पहले कि सबहेल इसे "पूंछ" के लिए लिखने के लिए खोल देगा, लेकिन सामग्री अभी भी खुली डिस्क्रिप्टर के माध्यम से उपलब्ध होगी जो "बिल्ली" को तब तक पारित कर दी जाएगी जब तक कि यह stdin बंद न हो जाए। वहाँ पाइपलाइन घटकों 'स्टार्टअप के बीच आदेश देने की कोई गारंटी नहीं है: तो आप बेहतर सुनिश्चित करें कि इस आदेश को खत्म हो जाएगा या "file.txt" की सामग्री को

  0

बेनामी डाउनवॉटर को दंडित किया जाना चाहिए। यह उत्तर काम करता है और इसमें तर्क है (यानी सामग्री तक पहुंच रखने के लिए इसे पढ़ने के लिए खोलने के बाद फ़ाइल हटाएं)। 22 apr. 132013-04-22 09:54:36

  0

मुझे (अनुमानित) प्रस्ताव के साथ असहमत होने में परेशानी है कि एक समाधान जिसमें विफलता के मामलों में डेटा हानि होती है, उससे बचा जाना चाहिए, भले ही उस चेतावनी को स्पष्ट रूप से लेबल किया गया हो; एक अनावश्यक सबहेल केक पर टुकड़ा कर रहा है। और "दंडित"? वास्तव में? 13 may. 132013-05-13 14:12:47

  0

@ चार्ल्सडफी, "शर्मिंदा दंडित" अज्ञात के लिए है। क्योंकि किसी भी तर्क के बिना डाउनवोट होने से परेशान होता है। आपको ऐसा नहीं लगता? .. शुद्धता के लिए, क्या आप सुनिश्चित हैं कि उच्च उत्तर और विश्वसनीयता - सही उत्तर के लिए आवश्यक है? कभी-कभी आप कुछ और संग्रह करने के लिए कुछ बलिदान कर सकते हैं। इस प्रकार विभिन्न विचारों से आप अलग-अलग समाधानों का इलाज कर सकते हैं। यदि आप मेरे विचार को मेरा उत्तर देते हैं तो आप पाएंगे कि इस उत्तर के लिए पूर्व शर्त पूरी नहीं की जा सकती है, इसलिए यह गलत तर्क है कि यह गलत है। 14 may. 132013-05-14 12:57:46

  0

... वैसे, स्पष्ट होने के लिए, मैं अज्ञात डाउनवोट नहीं था; मैं केवल उनके कार्यों को रक्षात्मक मानता हूं। 14 may. 132013-05-14 13:21:23

  0

@ चार्ल्स डफी, ठीक है, यह डाउनवॉटर के बारे में आपकी धारणा है। लेकिन वास्तविक कारण अलग हो सकता है। और यह समस्या है। 14 may. 132013-05-14 15:34:09

  0

थोड़ा सा गलत करने के लिए: "यदि बिल्डरों ने डेवलपर्स को सॉफ़्टवेयर बनाने का तरीका बनाया है, तो साथ आने वाले पहले लकड़ी के टुकड़े सभ्यता को नष्ट कर देंगे।" यह सुझाव देते हुए कि लोग निश्चित रूप से अनावश्यक रूप से नाजुक दृष्टिकोण का उपयोग करते हैं (अन्यथा करने के लिए एक विशिष्ट कारण अनुपस्थित) अनपेक्षित और अनियंत्रित विफलता मोड के साथ छेड़छाड़ किए गए सॉफ़्टवेयर और सिस्टम की ओर जाता है और इस प्रकार समस्या को कायम रखता है। 14 may. 132013-05-14 15:51:39

  0

@CharlesDuffy, फ़ाइल सामग्री को अपनी अंतिम पंक्ति के साथ बदलने का तथ्य पहले से ही एक गलत रास्ता है। यह या तो दो अलग-अलग फाइलें होनी चाहिए (अगर किसी को पूरी सामग्री की आवश्यकता है) या यह उस फ़ाइल में केवल एक पंक्ति होनी चाहिए (यानी पूरी सामग्री के बजाय उत्पादित एक पंक्ति) तो उस पर 'पूंछ -1' करने की आवश्यकता नहीं होगी। और मुझे पूरा यकीन है कि यहां विभिन्न प्रकार के संस्करण इस तथ्य से आते हैं कि यह एक मस्तिष्क टीज़र की तरह दिखता है। 14 may. 132013-05-14 17:00:59

  0

इनलाइन संपादन एक चीज है जो लोग करते हैं। 'पूंछ -1' विशेष रूप से अच्छा उपयोग मामला नहीं हो सकता है (वास्तव में, यह निश्चित रूप से नहीं है), लेकिन सिस्टम प्रशासन में करियर वाला कोई भी व्यक्ति असली, उत्पादन वातावरण और स्क्रिप्ट में पाए गए समान अभ्यासों का उपयोग करने जा रहा है नॉनट्रिविअल आवृत्ति। इस तरह, यह हमें अच्छी प्रथाओं को अपनाने और बुरे लोगों को अपनाने को हतोत्साहित करने के लिए - "ब्रेनटेज़र" या नहीं - हमें व्यवहार करता है। 14 may. 132013-05-14 17:28:49


1
echo "$(tail -1 file.txt)" > file.txt 
  0

क्या होता है यदि अंतिम पंक्ति में केवल '-n' है? क्या होगा यदि इसमें बैकस्लैश अक्षर शामिल हैं और आपका 'इको' एक्सएसआई पॉज़िक्स एक्सटेंशन के अनुरूप है (जो किसी भी भागने के लिए कॉल करता है तो उन अक्षरों को '-ई' जैसी किसी भी चीज़ के बिना भी सम्मानित किया जा सकता है)? प्रतिध्वनि पर भरोसा करने के बजाय 'printf '% s \ n'" $ (tail -1 file.txt) "का उपयोग करना सुरक्षित होगा 21 jul. 162016-07-21 14:47:42