दिलचस्प पोस्ट
अगर ऑब्जेक्ट एक jQuery ऑब्जेक्ट है, तो जांचें क्या आप ग्रूवी "प्रत्येक" क्लोजर से टूट सकते हैं? एंड्रॉइड पूर्व पॉपुलेटेड डाटाबेस अधिक से अधिक एप्लिकेशन कवरेज प्रदान करने के लिए libc के पुराने संस्करण के साथ लिंक करना मैं एक वस्तु को क्वेरी-स्ट्रिंग प्रारूप में कैसे सीरियल कर सकता हूं? एक 'अघोषित पहचानकर्ता' त्रुटि क्या है और मैं इसे कैसे ठीक कर सकता हूं? डुप्लिकेट कुंजी अद्यतन के साथ MySQL लोड डेटा INFILE टी-एसक्यूएल में एक समय कैसे गोल करें बाइट सरणी पैटर्न खोज क्या वास्तव में होता है जब आप malloc के बाद मुक्त नहीं होते हैं? WPF में एक अर्ध पारदर्शी विंडो कैसे तैयार करें जिससे माउस ईवेंट को पारित करने की अनुमति मिलती है कैसे ठीक से जोड़ने के लिए CMake के साथ निर्देशिका शामिल हैं? क्या यह व्यवहार में एसएचए टकराव की संभावना को नजरअंदाज करने के लिए सुरक्षित है? "X-content-type-options = nosniff" क्या है? उद्देश्य-सी एआरसी: मजबूत बनाम बनाए रखने और कमजोर बनाम असाइन

शैल स्क्रिप्ट लापता आखिरी पंक्ति पढ़ें

मेरे पास … एक बास खोल स्क्रिप्ट के साथ अजीब इकलौता है जो मुझे कुछ अंतर्दृष्टि प्राप्त करने की उम्मीद कर रहा था।

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

फाइल में लाइनों को पुनरावृति करने के लिए उपयोग किया गया कोड ( DATAFILE में संग्रहीत नाम था

 cat "$DATAFILE" | while read line 

हम कमांड लाइन से स्क्रिप्ट चला सकते हैं और यह फ़ाइल में हर पंक्ति को देखेगा, जिसमें आखिरी बार भी शामिल है, बस ठीक है। हालांकि, स्वचालित प्रक्रिया द्वारा चलाए जाने पर (जो स्क्रिप्ट चलाता है जो प्रश्न में स्क्रिप्ट से पहले DATAFILE बनाता है), आखिरी पंक्ति को कभी नहीं देखा जाता है।

हमने लाइनों के पुनरावृत्त करने के लिए निम्नलिखित का उपयोग करने के लिए कोड अपडेट किया है, और समस्या को साफ़ कर दिया है:

 for line in `cat "$DATAFILE"` 

नोट: फ़ाइल के अंत में DATAFILE की कोई नई पंक्ति कभी नहीं लिखी गई है।

मेरा प्रश्न दो भाग है … आखिरी पंक्ति मूल कोड द्वारा क्यों नहीं देखी जायेगी, और यह क्यों बदलेगा एक अंतर बना सकता है?

मैंने केवल सोचा था कि आखिरकार लाइन क्यों नहीं देखी जा सकती है, इस बारे में मुझे पता चला था:

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

ऐसा कहा जा रहा है, ऐसा लगता है, यदि आपके पास एक शेल स्क्रिप्ट में 2 कमांड हैं, तो पहले एक को पूरी तरह से बंद कर देना चाहिए, जब स्क्रिप्ट दूसरे नंबर पर चलता है।

प्रश्नों में कोई भी जानकारी, विशेष रूप से पहले, बहुत सराहना की जाएगी

वेब के समाधान से एकत्रित समाधान "शैल स्क्रिप्ट लापता आखिरी पंक्ति पढ़ें"

सी मानक का कहना है कि पाठ फ़ाइलों को एक नई लाइन या डेटा के साथ समाप्त होना चाहिए, क्योंकि आखिरी न्यूलाइन ठीक से पढ़ा नहीं जा सकता है

आईएसओ / आईईसी 9899: 2011 §7.21.2 स्ट्रीम

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

मुझे bash (या कोई यूनिक्स शेल) में परेशानी पैदा करने के लिए फ़ाइल के अंत में अनपेक्षित लापता नई रेखा नहीं होती, लेकिन ऐसा प्रतीत होता है कि यह समस्या पुन: पेशी के रूप में दिखती है ( $ इस आउटपुट में संकेत है):

 $ echo xxx\\c xxx$ { echo abc; echo def; echo ghi; echo xxx\\c; } > y $ cat y abc def ghi xxx$ $ while read line; do echo $line; done < y abc def ghi $ bash -c 'while read line; do echo $line; done < y' abc def ghi $ ksh -c 'while read line; do echo $line; done < y' abc def ghi $ zsh -c 'while read line; do echo $line; done < y' abc def ghi $ for line in $(<y); do echo $line; done # Preferred notation in bash abc def ghi xxx $ for line in $(cat y); do echo $line; done # UUOC Award pending abc def ghi xxx $ 

यह bash तक सीमित नहीं है – कॉर्न शेल ( ksh ) और zsh भी उस तरह व्यवहार करते हैं। मैं जीता हूँ, मैं सीखता हूँ; समस्या को बढ़ाने के लिए धन्यवाद

जैसा कि ऊपर कोड में दिखाया गया है, cat कमांड पूरी फ़ाइल पढ़ता है। for line in `cat $DATAFILE` तकनीक for line in `cat $DATAFILE` सभी आउटपुट एकत्र किए जाते हैं और एक रिक्त (मैं निष्कर्ष निकाला है कि फ़ाइल में प्रत्येक पंक्ति में कोई रिक्त नहीं है) के साथ सफेद अंतरिक्ष के मनमाना अनुक्रमों को बदल देता है

मैक ओएस एक्स 10.7.5 पर परीक्षण किया गया।


POSIX क्या कहते हैं?

पॉसिक्स read निर्देश विनिर्देश कहते हैं:

पढ़ा उपयोगिता मानक इनपुट से एक पंक्ति पढ़ी जाएगी।

डिफ़ॉल्ट रूप से, जब तक -r विकल्प निर्दिष्ट नहीं किया जाता है, <backslash> एक एस्केप वर्ण के रूप में कार्य करेगा। एक अपरिवर्तनीय <backslash> एक <newline> के अपवाद के साथ, निम्नलिखित वर्ण का शाब्दिक मूल्य बनाए रखेगा यदि <newline> <backslash> का पालन करता है, तो पढ़ने की उपयोगिता इस रूप में लाइन निरंतरता की व्याख्या करेगी। फ़ील्ड में इनपुट को विभाजित करने से पहले <backslash> और <newline> हटा दिया जाएगा। फ़ील्ड में इनपुट को विभाजित करने के बाद अन्य सभी अनपेक्षित <backslash> वर्ण हटा दिए जाएंगे।

यदि मानक इनपुट एक टर्मिनल डिवाइस है और इंवॉकिंग शेल इंटरैक्टिव है, तो एक निरंतरता लाइन के लिए पढ़ा जाएगा, जब वह <backslash> <newline> से समाप्त इनपुट लाइन को पढ़ता है, जब तक -r विकल्प निर्दिष्ट नहीं किया जाता है।

टर्मिनल <न्यूलाइन> (यदि कोई हो) इनपुट से हटा दी जाएगी और परिणाम पैरामीटर विस्तार के परिणाम के लिए शैल के रूप में फ़ील्ड में विभाजित किए जाएंगे (फ़ील्ड स्पीटिंग देखें); […]

ध्यान दें कि '(यदि कोई हो)' (उद्धरण में जोर दिया गया है)! ऐसा लगता है कि अगर कोई नई लाइन नहीं है, तो फिर भी परिणाम को पढ़ना चाहिए। दूसरी ओर, यह भी कहता है:

STDIN

मानक इनपुट एक पाठ फ़ाइल होगी।

और फिर आप इस बात के बारे में बहस पर वापस आ जाते हैं कि क्या एक फ़ाइल जो एक नई लाइन के साथ समाप्त नहीं होती है एक पाठ फ़ाइल है या नहीं

हालांकि, एक ही पृष्ठ दस्तावेजों पर तर्क:

यद्यपि मानक इनपुट को एक पाठ फ़ाइल होना आवश्यक है, और इसलिए हमेशा <newline> (जब तक कि यह एक खाली फ़ाइल नहीं है) के साथ समाप्त हो जाएगा, निरंतरता लाइनों के प्रसंस्करण जब -r विकल्प उपयोग नहीं किया जाता है, तो इनपुट नहीं हो सकता एक <newline> के साथ समाप्त ऐसा तब होता है जब इनपुट फ़ाइल की अंतिम पंक्ति को <backslash> <newline> के साथ समाप्त होता है यह इस कारण से है कि यदि "यदि कोई" उपयोग किया जाता है तो "टर्मिनलिंग <न्यूलाइन> (यदि कोई हो) में इनपुट से निकाल दिया जाएगा" विवरण में यह मानक इनपुट के लिए एक पाठ फ़ाइल होने की आवश्यकता का एक छूट नहीं है।

उस तर्क का मतलब यह होना चाहिए कि पाठ फ़ाइल को एक नई लाइन के साथ समाप्त करना चाहिए

एक पाठ फ़ाइल की POSIX परिभाषा है:

3.395 पाठ फ़ाइल

एक फ़ाइल जिसमें शून्य या अधिक पंक्तियों में व्यवस्थित वर्ण शामिल हैं लाइनों में NUL वर्ण नहीं होते हैं और कोई भी <LINE_MAX} बाइट्स लंबाई में, <newline> वर्ण सहित, से अधिक नहीं हो सकता। यद्यपि POSIX.1-2008 पाठ फ़ाइलों और बाइनरी फ़ाइलों (आईएसओ सी मानक देखें) के बीच भेद नहीं करता है, लेकिन कई यूटिलिडी केवल पाठ फ़ाइलों पर काम करते समय ही अनुमानित या अर्थपूर्ण आउटपुट का उत्पादन करते हैं। मानक उपयोगिताओं, जिनके पास ऐसी प्रतिबंध हैं, हमेशा अपने एसटीडीआईएन या INPUT FILES अनुभागों में "पाठ फ़ाइलें" निर्दिष्ट करते हैं।

यह 'सीधे एक न्यूलाइन' के साथ समाप्त नहीं करता है, लेकिन सी मानक को स्थगित करता है


'कोई टर्मिनल न्यूलाइन' समस्या का हल नहीं

नोट गॉर्डन Davisson का जवाब । एक साधारण परीक्षण से पता चलता है कि उनका अवलोकन सटीक है:

 $ while read line; do echo $line; done < y; echo $line abc def ghi xxx $ 

इसलिए, उसकी तकनीक:

 while read line || [ -n "$line" ]; do echo $line; done < y 

या:

 cat y | while read line || [ -n "$line" ]; do echo $line; done 

अंत में एक नई लाइन के बिना फ़ाइलों के लिए काम करेगा (कम से कम मेरी मशीन पर)


मुझे अब भी पता चलने में हैरान है कि गोले इनपुट के आखिरी खंड (इसे एक पंक्ति नहीं कहा जा सकता क्योंकि यह एक नई लाइन के साथ नहीं खत्म हो सकता है) को छोड़ देता है, लेकिन ऐसा करने के लिए संभवतः POSIX में पर्याप्त औचित्य हो सकता है। और स्पष्ट रूप से यह सुनिश्चित करना सबसे अच्छा होगा कि आपकी पाठ फ़ाइलें वास्तव में एक नई लाइन के साथ समाप्त हुई पाठ फ़ाइलें हैं

पढ़ने के आदेश के लिए पॉसिक्स स्पेक के अनुसार, "एंड-ऑफ-फाईल का पता लगाया गया है या कोई त्रुटि हुई है, अगर इसे गैर-ज़ोरो स्थिति वापस करनी चाहिए।" चूंकि यह आखिरी "रेखा" को पढ़ता है IOF से पता चलता है, यह $ पंक्ति सेट करता है और फिर एक त्रुटि स्थिति देता है, और त्रुटि स्थिति उस आखिरी "रेखा" पर निष्पादित करने से लूप को रोकती है इसका समाधान आसान है: यदि पावर्ड कमांड सफल होता है या अगर कुछ भी $ पंक्ति में पढ़ा जाता है तो लूप निष्पादित करें

 while read line || [ -n "$line" ]; do 

कुछ अतिरिक्त जानकारी जोड़ना:

  1. जबकि लूप के साथ cat का उपयोग करने की कोई आवश्यकता नहीं है while ...;do something;done<file पर्याप्त है
  2. इसके for लाइनें नहीं पढ़िए

जब लाइनों को पढ़ने के लिए लूप का उपयोग करते समय:

  1. IFS ठीक से सेट करें (आप अन्यथा इंडेंटेशन खो सकते हैं)
  2. पढ़ने के साथ आपको लगभग -r विकल्प का लगभग हमेशा उपयोग करना चाहिए

उपरोक्त आवश्यकताओं को पूरा करने के साथ एक उचित समय लूप इस तरह दिखेगा:

 while IFS= read -r line; do ... done <file 

और इसे अंत में एक नई लाइन के बिना फाइलों के साथ काम करने के लिए ( यहां से मेरे समाधान को पुन: स्थापित करना):

 while IFS= read -r line || [ -n "$line" ]; do echo "$line" done <file 

या लूप के साथ grep का उपयोग करते हुए:

 while IFS= read -r line; do echo "$line" done < <(grep "" file) 

एक फ़ाइल की अंतिम पंक्ति से मिलान करने के लिए sed का प्रयोग करें, जो तब एक नई पंक्ति जोड़ देगा यदि कोई मौजूद नहीं है और यह फ़ाइल के इनलाइन प्रतिस्थापन करता है:

sed -i '' -e '$a\' file

कोड इस स्टैक्स एक्सचेंज लिंक से है

नोट: मैंने खाली एकल उद्धरण -i '' को जोड़ दिया है क्योंकि, कम से कम ओएस एक्स में, -i बैकअप फाइल के लिए फ़ाइल एक्सटेंशन के रूप में -e उपयोग कर रहा था मैंने खुशी से मूल पोस्ट पर टिप्पणी की थी, लेकिन 50 अंक की कमी थी। शायद यह मुझे इस धागे में कुछ मिलेगा, धन्यवाद

मुझे संदेह है कि आपकी फ़ाइल की अंतिम पंक्ति में नई लाइन नहीं होने के कारण इस समस्या का कारण हो सकता है परीक्षण के लिए आप अपनी स्क्रिप्ट में मामूली संशोधन कर सकते हैं और इस तरह DATAFILE पढ़ सकते हैं:

 while read line do echo $line # do processing here done < "$DATAFILE" 

और देखो कि क्या यह कोई फर्क पड़ता है।

मैंने इसे कमांड लाइन में परीक्षण किया

 # create dummy file. last line doesn't end with newline printf "%i\n%i\nNo-newline-here" >testing 

अपने पहले फॉर्म के साथ टेस्ट करें (जबकि पाइपिंग-लूप)

 cat testing | while read line; do echo $line; done 

यह आखिरी पंक्ति को याद करती है, जो read बाद से समझ में आता है केवल एक नई लाइन के साथ समाप्त होने वाले इनपुट हो जाता है


अपने दूसरे फॉर्म के साथ टेस्ट करें (कमांड प्रतिस्थापन)

 for line in `cat testbed1` ; do echo $line; done 

यह आखिरी पंक्ति भी मिलती है


read केवल इनपुट प्राप्त हो जाता है यदि यह नई लाइन से समाप्त हो जाता है, इसलिए आप आखिरी पंक्ति को याद नहीं करते हैं

दूसरी ओर, दूसरे चरण में

 `cat testing` 

के रूप में फैलता है

 line1\nline2\n...lineM 

जो शेल द्वारा आईएफएस के उपयोग से कई क्षेत्रों में अलग किया जाता है, इसलिए आपको मिलता है

 line1 line2 line3 ... lineM 

यही कारण है कि आपको अभी भी अंतिम पंक्ति मिलती है

पी / एस: जो मुझे समझ में नहीं आता है कि आप पहले फार्म का काम कैसे करते हैं …

एक वैकल्पिक हल के रूप में, पाठ फ़ाइल से पढ़ने से पहले एक नई पंक्ति को फ़ाइल में जोड़ा जा सकता है।

 echo "\n" >> $file_path 

इससे यह सुनिश्चित होगा कि फाइल में पहले वाली सभी पंक्तियों को पढ़ा जाएगा।

मेरा मुद्दा भी ऐसा ही था। मैं एक फ़ाइल की एक बिल्ली कर रहा था, उसे एक तरह से पाइपिंग करता था और उसके परिणामस्वरूप 'var1 var2 var3 को पढ़ते समय' पाइपिंग करता था यानी: बिल्ली $ FILE | sort -k3 | जबकि पढ़े हुए आईपी नाम का नाम "do" के तहत काम एक अगर बयान है जो कि $ नाम क्षेत्र में बदलते हुए डेटा को पहचानता है और परिवर्तन के आधार पर या कोई परिवर्तन नहीं हुआ है $ संख्या या मुद्रित रिपोर्ट के लिए अभिव्यक्त लाइन मैं भी इस मुद्दे पर गया जहां मैं रिपोर्ट को प्रिंट करने के लिए अंतिम पंक्ति प्राप्त नहीं कर सका। मैं बिल्ली / सॉर्ट को एक नई फाइल में रीडायरेक्ट करने की सरल पूर्ति के साथ चला गया, उस नई फाइल में एक नई लाइन को गूंजती हुई और फिर सफल परिणामों के साथ नई फ़ाइल पर "मेरी आईपी नाम पढ़ा" कहता है। यानी: बिल्ली $ FILE | सॉर्ट -के 3> न्यूफ़ाइल ईको "\ n" >> न्यूफ़ाइल बिल्ली न्यूफ़ाइल, जबकि पढ़ी गई संख्या आईपी नाम करें कभी-कभी सरल, असभ्य जाने का सबसे अच्छा तरीका है