यह जांचने के लिए कि क्या कोई फ़ाइल CRLF या LF का उपयोग किए बिना उसे संशोधित करती है?


48

मुझे समय-समय पर एक कमांड चलाने की ज़रूरत है जो यह सुनिश्चित करता है कि कुछ पाठ फ़ाइलों को लिनक्स मोड में रखा जाए। दुर्भाग्य से dos2unixहमेशा फ़ाइल को संशोधित करता है, जो फ़ाइल और फ़ोल्डर के टाइमस्टैम्प को गड़बड़ कर देगा और अनावश्यक लेखन का कारण होगा।

मेरे द्वारा लिखी गई स्क्रिप्ट बैश में है, इसलिए मैं बैश के आधार पर उत्तर पसंद करूंगा।

जवाबों:


41

आप dos2unixफ़िल्टर के रूप में उपयोग कर सकते हैं और इसके आउटपुट की तुलना मूल फ़ाइल से कर सकते हैं:

dos2unix < myfile.txt | cmp -s - myfile.txt

2
बहुत स्मार्ट और उपयोगी, क्योंकि यह पूरी फ़ाइल का परीक्षण करता है और न केवल पहली या कुछ पंक्ति।
आधा

2
हो सकता है आप बदल सकते testद्वारा myfile.txtके साथ से बचने के भ्रम को अपने उदाहरण में दो बार /usr/bin/test
पीटरिनो

1
NB आपको -sआउटपुट देखने के लिए ध्वज को हटाने की आवश्यकता होगी । मैन पेज से: -s, --quiet, --silent suppress all normal output
tobalr

24

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

यदि फ़ाइल का कोई भी संशोधन अस्वीकार्य है, तो आप इस उत्तर से निम्नलिखित समाधान का उपयोग कर सकते हैं ।

find . -not -type d -exec file "{}" ";" | grep CRLF

1
क्या आपका मतलब है कि आप सचमुच CRLF को 4 अक्षर C, R, L और F लिखते हैं?
बोदासाइडो

7
क्या आपका यह भी मतलब है कि क्रेप उसी तरह सीआर और एलएफ ले सकता है?
बोदासाइडो

@bodacydo यह उनके द्वारा लिंक किए गए उत्तर में समझाया गया है, और अब स्कॉट के BertS के उत्तर में भी यहां unix.stackexchange.com/a/79708/59699 है
dave_thompson_085

@ dave_thompson_085 मैं स्पष्टीकरण नहीं देखता। इसमें केवल CRLF का उल्लेख है, लेकिन यह क्या है समझाता नहीं है।
bodacydo

1
@bodacydo stackoverflow.com/questions/73833/… का कहना है कि find ... -exec file ... | grep CRLFडॉस लाइन एंडिंग (यानी बाइट्स 0 डी 0 ए) के साथ एक फ़ाइल के लिए "आपको कुछ ऐसा मिलेगा: ./1/dos1.txt: ASCII text, with CRLF line terminators जैसा कि आप देख सकते हैं कि इसमें वास्तविक स्ट्रिंग CRLF शामिल है और इसलिए इसकी grepतलाश है सरल स्ट्रिंग CRLF।
dave_thompson_085

22

आप grepCRLF कोड, ऑक्टल के लिए प्रयास कर सकते हैं :

grep -U $'\015' myfile.txt

या हेक्स:

grep -U $'\x0D' myfile.txt

बेशक, धारणा यह है कि यह एक पाठ फ़ाइल है।
mdpc

2
मुझे यह grepउपयोग पसंद है क्योंकि यह मुझे निर्देशिका में ऐसी सभी फाइलों को आसानी से सूचीबद्ध करने grep -lU $'\x0D' *और आउटपुट को पास करने की अनुमति देता है xargs
मेलेबियस

खोज पैटर्न से पहले $ का क्या अर्थ है? @don_crissti
fersarr

1
@ स्थानांतरण - unix.stackexchange.com/a/401451/22142
don_crissti

21

चूंकि संस्करण 7.1dos2unix में एक -i, --infoलाइन ब्रेक के बारे में जानकारी प्राप्त करने का विकल्प है। आप dos2unix का उपयोग करके परीक्षण कर सकते हैं कि किन फ़ाइलों को रूपांतरण की आवश्यकता है।

उदाहरण:

dos2unix -ic *.txt | xargs dos2unix


13

पहली विधि ( grep):

उन लाइनों की गणना करें जिनमें एक गाड़ी वापसी है:

[[ $(grep -c $'\r' myfile.txt) -gt 0 ]] && echo dos

उन लाइनों की गणना करें जो एक गाड़ी वापसी के साथ समाप्त होती हैं:

[[ $(grep -c $'\r$' myfile.txt) -gt 0 ]] && echo dos

ये आमतौर पर समतुल्य होंगे; एक लाइन के इंटीरियर में एक गाड़ी वापसी (यानी, अंत में नहीं) दुर्लभ है।

अधिक कुशल:

grep -q $'\r' myfile.txt && echo dos

यह अधिक कुशल है

  1. क्योंकि उसे ASCII स्ट्रिंग में गिनती बदलने की आवश्यकता नहीं है, और फिर उस स्ट्रिंग को पूर्णांक में परिवर्तित करें, और इसकी तुलना शून्य से करें, और
  2. क्योंकि grep -cपैटर्न की सभी घटनाओं को grep -qदेखने के लिए बाहर निकलने के लिए पैटर्न की सभी घटनाओं को गिनने के लिए पूरी फाइल को पढ़ने की जरूरत है ।

टिप्पणियाँ:

  • उपर्युक्त के दौरान, आपको -Uविकल्प (यानी, उपयोग -cUया -qU) को जोड़ने की आवश्यकता हो सकती है , क्योंकि GNU का grepअनुमान है कि क्या फ़ाइल एक पाठ फ़ाइल है। यदि यह सोचता है कि फ़ाइल पाठ है, तो यह $नियमित अभिव्यक्तियों को "सही ढंग से" काम करने के प्रयास में, लाइनों के सिरों पर गाड़ी के रिटर्न की अनदेखी करता है - भले ही नियमित अभिव्यक्ति हो \r$! निर्दिष्ट -U(या --binary) इस अनुमान को खत्म कर देता है, जिससे grepफ़ाइल को बाइनरी के रूप में माना जाता है और सीआर-एंडिंग के साथ डेटा को मिलान तंत्र शब्दशः में पास कर देता है।
  • मत करो grep … $'\r\n' myfile.txt, क्योंकि एक पैटर्न सीमांकक के रूप में grepव्यवहार करता \nहै। जिस तरह एक नल स्ट्रिंग या एक नल स्ट्रिंग grep -E 'foo|'युक्त लाइनों की तलाश करता है, ठीक उसी तरह की लाइनों वाला fooया अशक्त स्ट्रिंग grep $'\r\n'दिखता है \r, और हर पंक्ति एक नल स्ट्रिंग से मेल खाती है।

दूसरी विधि ( file):

[[ $(file myfile.txt) =~ CRLF ]] && echo dos

क्योंकि fileरिपोर्ट कुछ इस तरह है:

myfile.txt: UTF-8 Unicode text, with CRLF line terminators

सुरक्षित संस्करण:

[[ $(file -b - < myfile.txt) =~ CRLF ]] && echo dos

कहाँ पे

खबरदार कि file एक गैर-अंग्रेजी लोकेल में आउटपुट से जाँच नहीं हो सकती है।


1
आप "$(echo -e '\r')"बहुत सरलता से बदल सकते हैं $'\r', हालांकि व्यक्तिगत रूप से मैं $'\r\n'झूठी सकारात्मक की संख्या को कम करने के लिए उपयोग करूंगा ।
रिंकी

@rici grep $'\r\n'अपने सिस्टम पर सभी फ़ाइलों मिलान करने के लिए लगता है ...
depquid

@rici: अच्छी पकड़। मैंने आपके सुझाव के अनुसार अपना उत्तर संपादित किया। - depquid: शायद आप विंडोज पर हैं? :-) रिसी के टिप यहां काम करते हैं।
बर्ट्स

@depquid (और बर्ट्स): वास्तव में, मुझे लगता है कि सही-सही मंगलाचरण है grep -U $'\r$', जिससे grepदूसरे-लाइन-एंडिंग का अनुमान लगाने से रोका जा सके ।
रिसी

इसके अलावा, -qयदि आप एक मैच पाया जाता है, तो आप रिटर्न कोड को सेट करने के लिए उपयोग कर सकते हैं , -cजिसके बजाय एक अतिरिक्त चेक की आवश्यकता होती है। व्यक्तिगत रूप से मुझे आपका दूसरा समाधान पसंद है, हालाँकि यह बहुत हद तक इस बात पर निर्भर करता है कि fileयह गैर-अंग्रेजी लोकेल में काम नहीं करता है।
रिसी

11

उपयोग cat -A

$ cat file
hello
hello

अब यदि यह फाइल * NIX सिस्टम में बनाई गई है, तो यह प्रदर्शित होगी

$ cat -A file
hello$
hello$

लेकिन अगर यह फ़ाइल विंडोज में बनाई गई थी, तो यह प्रदर्शित होगी

$ cat -A file
hello^M$
hello

^Mका प्रतिनिधित्व करता है CRऔर $प्रतिनिधित्व करता है LF। ध्यान दें कि विंडोज ने अंतिम पंक्ति को नहीं बचाया थाCRLF

यह फ़ाइल सामग्री को भी नहीं बदलता है।


सबसे अच्छा और सरल उपाय! वोट की जरूरत है।
user648026

1
+1 अब तक का सबसे अच्छा जवाब। कोई निर्भरता नहीं, कोई जटिल बैश स्क्रिप्ट नहीं। सिर्फ -Aबिल्ली के लिए। cat -A file | lessयदि फ़ाइल बहुत बड़ी है, तो एक टिप का उपयोग करना होगा । मुझे यकीन है कि विशेष रूप से लंबी फ़ाइल के लिए फ़ाइल अंत की जाँच करना असामान्य नहीं है। ( qकम छोड़ने के लिए दबाएं )
निकोलस पिपिटोन

4

आप के लिए एक पार्टी समारोह:

# return 0 (true) if first line ends in CR
isDosFile() {
    [[ $(head -1 "$1") == *$'\r' ]]  
}

फिर आप सामान की तरह कर सकते हैं

streamFile () {
    if isDosFile /tmp/foo.txt; then
        sed 's/\r$//' "$1"
    else
        cat "$1"
    fi
}

streamFile /tmp/foo.txt | process_lines_without_CR

3
आपको isDosFile()अपने उदाहरण में उपयोग करने की आवश्यकता नहीं है streamFile() { sed 's/\r$//' "$1" ; }:।

1
मुझे लगता है कि यह सबसे सुंदर समाधान है; यह पूरी फ़ाइल नहीं पढ़ता है, केवल पहली पंक्ति है।
एडम रिक्ज़ोस्की

4

यदि किसी फ़ाइल में DOS / Windows- शैली CR-LF लाइन एंडिंग है, तो यदि आप इसे यूनिक्स-आधारित टूल का उपयोग करके देखते हैं तो आपको प्रत्येक पंक्ति के अंत में CR ('r') वर्ण दिखाई देंगे।

यह आदेश:

grep -l '^M$' filename

प्रिंट होगा filenameअगर फ़ाइल Windows शैली लाइन अंत के साथ एक या अधिक पंक्तियों में शामिल है, और कुछ भी नहीं प्रिंट होगा अगर ऐसा नहीं होता। सिवाय इसके कि ^Mएक शाब्दिक गाड़ी वापसी चरित्र, आम तौर पर टाइपिंग द्वारा टर्मिनल में प्रवेश किया हो गया है Ctrl+ Vके बाद Enter (या Ctrl+ Vऔर फिर Ctrl+ M)। बैश शेल आपको एक शाब्दिक कैरिज रिटर्न लिखने के लिए अनुमति देता है $'\r'( यहाँ दस्तावेज के रूप में ), ताकि आप लिख सकें:

grep -l $'\r$' filename

अन्य गोले एक समान सुविधा प्रदान कर सकते हैं।

आप इसके बजाय किसी अन्य टूल का उपयोग कर सकते हैं:

awk '/\r$/ { exit(1) }' filename

इस स्थिति के साथ बाहर निकल जाएगा 1(सेटिंग $?करने के लिए 1) यदि फ़ाइल किसी भी Windows शैली लाइन अंत होता है, और की स्थिति के साथ 0करता है, तो यह नहीं है, यह एक खोल में उपयोगी बनाने ifबयान (की कमी ध्यान दें [कोष्ठक ]):

if awk '/\r$/ { exit(1) }' filename ; then
    echo filename has Unix-style line endings
else
    echo filename has at least one Windows-style line ending
fi

एक फ़ाइल में यूनिक्स-शैली और विंडोज-स्टाइल लाइन एंडिंग्स का मिश्रण हो सकता है। मैं यहाँ यह मान रहा हूँ कि आप ऐसी फ़ाइलों का पता लगाना चाहते हैं जिनमें कोई भी विंडोज-स्टाइल लाइन अंत है।


1
आप $'\r'इस प्रश्न के अन्य उत्तरों में बताए अनुसार टाइप करके गाड़ी की वापसी को bash (और कुछ अन्य गोले) में कमांड लाइन पर अंकित कर सकते हैं।
स्कॉट


1

मैं उपयोग कर रहा हूं

cat -v filename.txt | diff - filename.txt

जो काम करने लगता है। मुझे आउटपुट पढ़ने में थोड़ा आसान लगता है

dos2unix < filename.txt | diff - filename.txt

यदि आप dos2unixकिसी कारण से स्थापित नहीं कर सकते हैं तो यह उपयोगी है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.