unix - मेरा टूल आउटपुट स्वयं को ओवरराइट क्यों करता है और मैं इसे कैसे ठीक करूं?




awk sed (2)

इस प्रश्न का आशय दैनिक प्रश्नों का उत्तर प्रदान करना है, जिसका उत्तर "आपके पास DOS लाइन एंडिंग्स हैं", इसलिए हम केवल उन्हीं उत्तरों के डुप्लिकेट के रूप में उन्हें बंद कर सकते हैं, जो बिना उत्तर उत्तरों को दोहराए।

नोट: यह किसी मौजूदा प्रश्न का डुप्लिकेट नहीं है । इस प्रश्नोत्तर का आशय केवल "इस उपकरण को चलाना" उत्तर प्रदान करना नहीं है, बल्कि इस मुद्दे को समझाने के लिए भी है कि हम किसी को भी संबंधित प्रश्न के साथ यहाँ इंगित कर सकते हैं और वे इस बात का स्पष्ट विवरण पाएंगे कि उन्हें यहाँ क्यों इंगित किया गया था? उपकरण के रूप में चलाने के लिए उनकी समस्या को हल करते हैं। मैंने मौजूदा क्यू एंड ए के सभी को पढ़ने में घंटों बिताए और वे सभी मुद्दे की व्याख्या में कमी कर रहे हैं, वैकल्पिक उपकरण जिनका उपयोग इसे हल करने के लिए किया जा सकता है, और / या संभावित समाधानों के पेशेवरों / विपक्ष / कैवियट्स। साथ ही उनमें से कुछ ने ऐसे उत्तर स्वीकार कर लिए हैं जो सीधे सादे खतरनाक हैं और उनका उपयोग कभी नहीं किया जाना चाहिए।

अब उस विशिष्ट प्रश्न पर वापस जाएँ , जिसके परिणामस्वरूप यहाँ एक संदर्भ दिया जाएगा:

मेरे पास 1 पंक्ति वाली फ़ाइल है:

what isgoingon

और जब मैं इसे इस awk स्क्रिप्ट का उपयोग करके प्रिंट करता हूं तो खेतों के क्रम को उल्टा करने के लिए:

awk '{print $2, $1}' file

इसके बजाय मुझे उम्मीद है कि आउटपुट देखने के लिए:

isgoingon what

मुझे वह फ़ील्ड मिलती है जो पंक्ति के अंत में होनी चाहिए, लाइन के शुरू में दिखाई देती है, लाइन के शुरू में कुछ टेक्स्ट ओवरराइट कर रहा है:

 whatngon

या मुझे 2 लाइनों पर आउटपुट स्प्लिट मिलता है:

isgoingon
 what

समस्या क्या हो सकती है और मैं इसे कैसे ठीक करूं?

https://code.i-harness.com


आप अज्ञात लाइन एंडिंग वाली फ़ाइलों के लिए PCRE में \R आशुलिपि वर्ण वर्ग का उपयोग कर सकते हैं। यूनिकोड या अन्य प्लेटफार्मों के साथ विचार करने के लिए और भी अधिक रेखाएं समाप्त होती हैं। एक सामान्य न्यूलाइन के सभी रूपों का प्रतिनिधित्व करने के लिए यूनिकोड कंसोर्टियम से \R फॉर्म एक अनुशंसित वर्ण वर्ग है।

इसलिए यदि आपके पास एक 'अतिरिक्त' है, तो आप इसे regex s/\R$/\n/ साथ पा सकते हैं और हटा सकते हैं, लाइन एंडिंग्स के किसी भी संयोजन को \n में सामान्य कर देंगे। वैकल्पिक रूप से, आप 'लाइन एंडिंग' की किसी भी धारणा को कैप्चर करने के लिए s/\R/\n/g का उपयोग कर सकते हैं और एक \n वर्ण में मानकीकृत कर सकते हैं।

दिया हुआ:

$ printf "what\risgoingon\r\n" > file
$ od -c file
0000000    w   h   a   t  \r   i   s   g   o   i   n   g   o   n  \r  \n
0000020

पर्ल और रूबी और PCRE के अधिकांश फ्लेवर स्ट्रिंग \R $ जों के अंत (मल्टी-लाइन मोड में लाइन के अंत) के साथ संयुक्त रूप से लागू होते हैं:

$ perl -pe 's/\R$/\n/' file | od -c
0000000    w   h   a   t  \r   i   s   g   o   i   n   g   o   n  \n    
0000017
$ ruby -pe '$_.sub!(/\R$/,"\n")' file | od -c
0000000    w   h   a   t  \r   i   s   g   o   i   n   g   o   n  \n    
0000017

(ध्यान दें कि दो शब्दों के बीच \r सही ढंग से अकेला छोड़ दिया गया है)

यदि आपके पास \R नहीं है, तो आप PCRE में (?>\r\n|\v) के बराबर का उपयोग कर सकते हैं।

सीधे POSIX टूल के साथ, आपकी सबसे अच्छी शर्त संभावना की तरह awk रही है:

$ awk '{sub(/\r$/,"")} 1' file | od -c
0000000    w   h   a   t  \r   i   s   g   o   i   n   g   o   n  \n    
0000017

चीजें जो काम करती हैं (लेकिन अपनी सीमाओं को जानें):

tr अन्य संदर्भ में उपयोग किए जाने पर भी सभी \r को हटा देता है ( \r का उपयोग दुर्लभ है, और XML प्रसंस्करण के लिए आवश्यक है कि \r हटा दिया जाए, इसलिए tr एक महान समाधान है):

$ tr -d "\r" < file | od -c
0000000    w   h   a   t   i   s   g   o   i   n   g   o   n  \n        
0000016

GNU sed काम करता है, लेकिन POSIX sed नहीं, क्योंकि \r और \x0D POSIX पर समर्थित नहीं हैं।

GNU sed केवल:

$ sed 's/\x0D//' file | od -c   # also sed 's/\r//'
0000000    w   h   a   t  \r   i   s   g   o   i   n   g   o   n  \n    
0000017

यूनिकोड रेगुलर एक्सप्रेशन गाइड शायद सबसे अच्छी शर्त है कि "न्यूलाइन" का निश्चित उपचार क्या है।


समस्या यह है कि आपकी इनपुट फ़ाइल सिर्फ LF के UNIX लाइन अंत के बजाय CRLF DOS लाइन एंडिंग का उपयोग करती है और आप इस पर UNIX टूल चला रहे हैं, इसलिए CR UNIX टूल द्वारा संचालित किए जा रहे डेटा का हिस्सा बना हुआ है। CR को आमतौर पर \r द्वारा निरूपित किया जाता है और इसे एक नियंत्रण-एम ( ^M ) के रूप में देखा जा सकता है जब आप फ़ाइल पर cat -vE चलाते हैं जबकि LF \n और cat -vE साथ $ रूप में दिखाई देता है।

तो आपकी इनपुट फाइल वास्तव में सिर्फ इतनी ही नहीं थी:

what isgoingon

यह वास्तव में था:

what isgoingon\r\n

जैसा कि आप cat -v साथ देख सकते हैं cat -v :

$ cat -vE file
what isgoingon^M$

और od -c :

$ od -c file
0000000   w   h   a   t       i   s   g   o   i   n   g   o   n  \r  \n
0000020

इसलिए जब आप फ़ाइल पर एक UNIX टूल जैसे कि awk (जो लाइन समाप्त होने के रूप में मानते हैं) चलाते हैं, तो लाइन को पढ़ने के कार्य द्वारा \n का उपभोग किया जाता है, लेकिन वह 2 फ़ील्ड को छोड़ देता है:

<what> <isgoingon\r>

दूसरे फ़ील्ड के अंत में \r नोट करें। \r मतलब है Carriage Return जो शाब्दिक रूप से लाइन के प्रारंभ में कर्सर को वापस करने के लिए एक निर्देश है जब आप ऐसा करते हैं:

print $2, $1

awk isgoingon प्रिंट isgoingon और फिर कर्सर को प्रिंट करने से पहले लाइन के शुरू में isgoingon , यही कारण है कि जो isgoingon की शुरुआत को अधिलेखित करने के लिए प्रकट होता है।

समस्या को ठीक करने के लिए, इनमें से कुछ करें:

dos2unix file
sed 's/\r$//' file
awk '{sub(/\r$/,"")}1' file
perl -pe 's/\r$//' file

स्पष्ट रूप से dos2unix कुछ यूनिक्स वेरिएंट (जैसे उबंटू) में उर्फ frodos है।

सावधान रहें यदि आप tr -d '\r' का उपयोग करने का निर्णय लेते हैं, जैसा कि अक्सर सुझाव दिया जाता है कि यह आपकी फ़ाइल के सभी \r को हटा देगा, न कि प्रत्येक पंक्ति के अंत में।

ध्यान दें कि GNU awk आपको उन फ़ाइलों को पार्स करने देगा जिनकी DOS लाइन एंडिंग केवल उचित रूप से RS सेट करके है:

gawk -v RS='\r\n' '...' file

लेकिन अन्य awks यह अनुमति नहीं देंगे कि POSIX के लिए केवल एक ही पात्र RS का समर्थन करने के लिए awks की आवश्यकता होती है और अधिकांश अन्य awks चुपचाप RS='\r\n' से RS='\r' काट देंगे। आपको -v BINMODE=3 लिए -v BINMODE=3 को जोड़ने की आवश्यकता हो सकती है, यहां तक ​​कि \r s को देखने के लिए भी क्योंकि अंतर्निहित C प्राइमेटिव्स उन्हें कुछ प्लेटफार्मों, जैसे साइबरविन पर स्ट्रिप करेगा।

देखने वाली एक बात यह है कि एक्सेल जैसे विंडोज टूल द्वारा बनाए गए CSV लाइन अंत के रूप में CRLF का उपयोग करेंगे लेकिन CRLF एक विशिष्ट क्षेत्र के अंदर LF एम्बेड कर सकते हैं, जैसे:

"field1","field2.1
field2.2","field3"

सच है:

"field1","field2.1\nfield2.2","field3"\r\n

इसलिए यदि आप सिर्फ \r\n s में कनवर्ट करते हैं, तो आप लाइनफीड्स से खेतों के भीतर लाइनफीड्स को लाइन एंडिंग के रूप में नहीं बता सकते हैं, इसलिए यदि आप ऐसा करना चाहते हैं, तो मैं पहले सभी को इंट्रा-फील्ड लाइनफीड्स में परिवर्तित करने की सलाह देता हूं। उदाहरण के लिए, यह सभी इंट्रा-फील्ड LFs को टैब में बदल देगा और CRLF को समाप्त करने वाली सभी लाइन को LF s में बदल देगा:

gawk -v RS='\r\n' '{gsub(/\n/,"\t")}1' file

GNU के बिना भी ऐसा ही करना एक अभ्यास के रूप में बचा है, लेकिन अन्य awks के साथ इसमें उन लाइनों को संयोजित करना शामिल है जो CR में समाप्त नहीं होते हैं क्योंकि वे पढ़े जाते हैं।







dos2unix