उन फ़ाइलों को कैसे खोजें, जिनमें अंत में खाली रेखा नहीं है?


9

मेरे पास वर्तमान निर्देशिका की उपनिर्देशिकाओं में फाइलें हैं जिनके अंत में नई लाइनें हो सकती हैं या नहीं; मैं ऐसी फाइलें कैसे पा सकता हूं जिनमें अंत में कोई नई रेखा न हो?

मैंने यह कोशिश की है:

find . -name '*.styl' | while read file; do
    awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done

लेकिन यह काम नहीं करता है। awk 'END{print}' $fileखाली नई लाइन से पहले लाइन प्रिंट करता है, उसी के रूप में tail -n 1 $file


@don_crissti मुझे उन फ़ाइलों की आवश्यकता है जिनके पास खाली रेखा नहीं है।
ज्यूबिक

2
क्या मुझे उन फ़ाइलों को खोजने की आवश्यकता का कारण पूछना चाहिए? मुझे लगता है कि यह इस तथ्य के साथ करना है कि यूनिक्स में पाठ फ़ाइलों को एक नई लाइन के साथ समाप्त किया जाना चाहिए (vi विल "जब आप बचाते हैं, तो एक को जोड़ दें", उदाहरण के लिए), और कई (पाठ-उन्मुख) आदेशों की उपेक्षा करेंगे अंतिम पंक्ति यदि इसे एक नई पंक्ति (wc, iirc .... द्वारा समाप्त नहीं किया गया है लेकिन अन्य हैं)। और इससे मदद मिल सकती है
ओलिवियर दुलाक

awk 'END{print}' $file : यह पूरी तरह से $ फ़ाइल की सामग्री को अनदेखा करता है, और "$ फ़ाइल" में निहित सभी फ़ाइलों को पार्स करने के बाद यह एक नई पंक्ति जोड़ता है। जैसा कि यह एकमात्र चीज है जो कमांड प्रिंट को printf '\n'जगाती है , इसे इसके साथ प्रतिस्थापित किया जा सकता है: ($ में किसी भी फ़ाइल के मेंटिनो के बिना) और एक ही काम करें। मुझे लगता है कि यह वह नहीं है जो आप लक्ष्य कर रहे थे (यानी: फ़ाइल की अंतिम पंक्ति प्रिंट करें?)
ओलिवियर दुलैक

@don_crissti: यदि किसी फ़ाइल का अंतिम वर्ण कोई नई पंक्ति नहीं है, तो वह फ़ाइल सख्ती से यूनिक्स पाठ फ़ाइल नहीं है। देखें: unix.stackexchange.com/a/263919/27616 । ध्यान दें कि कई पाठ कमांड (उदाहरण के लिए, wc) केवल उस अंतिम "लाइन" को अनदेखा करते हैं, यदि वह एक नई पंक्ति द्वारा समाप्त नहीं होती है
ओलिवियर ड्यूलैक

1
@OlivierDulac: gawk प्रिंट cकरता है और ऐसा FreeBSD करता है, लेकिन मैंने इस पर ध्यान नहीं दिया कि इसे कार्यान्वयन-निर्भरता के रूप में प्रलेखित किया गया है: gnu.org/software/gawk/manual/… । तो ऐसा होता है लेकिन हमेशा नहीं।
dave_thompson_085

जवाबों:


14

स्पष्ट करने के लिए, LF (उर्फ \nया न्यूलाइन) वर्ण रेखा सीमांकक है , यह रेखा विभाजक नहीं है। जब तक यह एक newline वर्ण द्वारा समाप्त नहीं किया जाता है तब तक एक पंक्ति समाप्त नहीं होती है। एक फ़ाइल जिसमें केवल a\nbसम्‍मिलित पाठ फ़ाइल नहीं है क्‍योंकि इसमें अंतिम पंक्ति के बाद वर्ण हैं। उसी फ़ाइल के लिए समान जिसमें केवल शामिल है a। एक फ़ाइल a\nजिसमें एक गैर-रिक्त रेखा है।

तो एक फाइल जो कम से कम एक खाली लाइन के साथ समाप्त होती है, दो न्यूलाइन वर्णों के साथ समाप्त होती है या जिसमें एक नया लाइन वर्ण होता है।

अगर:

 tail -c 2 file | od -An -vtc

आउटपुट \nया \n \n, फिर फ़ाइल में कम से कम एक अनुगामी खाली रेखा होती है। यदि यह कुछ भी आउटपुट नहीं करता है, तो यह एक खाली फ़ाइल है, यदि यह आउटपुट करता है <anything-but-\0> \n, तो यह एक गैर-खाली लाइन में समाप्त होता है। और कुछ भी, यह एक पाठ फ़ाइल नहीं है।

अब, एक खाली लाइन में समाप्त होने वाली फ़ाइलों को खोजने के लिए उपयोग करने के लिए, ठीक है यह कुशल है (विशेष रूप से बड़ी फ़ाइलों के लिए) कि यह केवल फाइलों के अंतिम दो बाइट्स को पढ़ता है, लेकिन पहले आउटपुट आसानी से पार्स प्रोग्राम नहीं है विशेष रूप से यह देखते हुए। odअगले एक कार्यान्वयन से संगत नहीं है , और हमें प्रति फ़ाइल एक tailऔर एक चलाने की आवश्यकता होगी od

find . -type f -size +0 -exec gawk '
  ENDFILE{if ($0 == "") print FILENAME}' {} +

(खाली लाइन में समाप्त होने वाली फ़ाइलों को खोजने के लिए) संभव के रूप में कुछ कमांड चलाएंगे, लेकिन इसका मतलब होगा कि सभी फ़ाइलों की पूरी सामग्री को पढ़ना।

आदर्श रूप में, आपको एक शेल की आवश्यकता होगी जो किसी फ़ाइल के अंत को स्वयं पढ़ सके।

के साथ zsh:

zmodload zsh/system
for f (**/*(D.L+0)) {
  {
    sysseek -w end -2
    sysread
    [[ $REPLY = $'\n' || $REPLY = $'\n\n' ]] && print -r -- $f
  } < $f
}

इस उत्तर की विधि का उपयोग करने का एक तरीका यह जानने के लिए कि क्या कुछ फ़ाइल पाठ फाइलें हैं are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }:। के रूप में उपयोग करें:if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
ओलिवियर दुलक

6

के साथ gnu sedऔर एक खोल की तरह zsh(या bashसाथ shopt -s globstar):

sed -ns '${/./F}' ./**/*.styl

यह जाँचता है कि क्या प्रत्येक फ़ाइल की अंतिम पंक्ति खाली नहीं है, यदि यह फ़ाइल नाम को प्रिंट करता है।
यदि आप विपरीत चाहते हैं (यदि अंतिम पंक्ति खाली है तो फ़ाइल नाम प्रिंट करें) बस के /./साथ बदलें/^$/


1
-sपहले कभी एक्शन में नहीं देखा गया। जीएनयू धन्यवाद!
ग्लेन जैकमैन

नोट: एफ विकल्प sed संस्करण 4.2.2 (22 दिसंबर, 2012) से मौजूद है
आइजैक

3

खाली अंतिम पंक्ति के साथ एक सही ढंग से समाप्त पाठ फ़ाइल दो में समाप्त होती है \n

फिर, हम उम्मीद करते हैं कि tail -c2इसके बराबर होना चाहिए $'\n\n'

अफसोस की बात है कि विस्तारक नई लाइनों को पीछे हटाते हैं। हमें थोड़ा ट्विकिंग की आवश्यकता होगी।

f=filename
nl='
'
t=$(tail -c2 $f; printf x)  # capture the last two characters.
r="${nl}${nl}$"                 # regex for: "ends in two newlines".
[[ ${t%x} =~ $r ]] &&  echo "file $f ends in an empty line"

हम यह जाँचने के लिए भी थोड़ा विस्तार कर सकते हैं कि कौन सी फाइलें एक नई पंक्ति के लिए विफल हैं:

nl='
'
nl=$'\n'
find . -type f -name '*.styl' | while read f; do
    t=$(tail -c2 $f; printf x); r1="${nl}$"; r2="${nl}${r1}"
    [[ ${t%x} =~ $r1 ]] || echo "file $f is missing a trailing newline"
    [[ ${t%x} =~ $r2 ]] && echo "$f"
done

ध्यान दें कि $'\r\nयदि आवश्यक हो तो न्यूलाइन को कुछ इस तरह बदला जा सकता है ।
उस स्थिति में भी बदल tail -c2जाते हैं tail -c4


0
for file in *; do
    # Check if the file is readable to avoid clutter
    if cat "./$file" 2&>1 /dev/null; then
        # Compare the last character with a single newline character.
        if [ -n "$(tail -c 1 -- "./$file")" ]; then
            echo "$file"
        fi
        # Also report empty files.
        if [ $(wc -c  < "./$file") -eq 0 ]; then
            echo "$file"
        fi
    fi
done

1
यह खाली फाइलों के साथ काम नहीं करता है लेकिन मैं इसके साथ रह सकता हूं।
ज्यूबिक

कुछ और त्रुटियां हो सकती हैं क्योंकि स्ट्रिंग तुलना उस तरह से काम नहीं करती है जैसी मुझे उम्मीद थी। मैंने खाली फाइलों के लिए एक चेक जोड़ा।
Oskar Skog

आह, यह newline वर्णों की उपेक्षा करता है।
Oskar Skog

अधिक पठनीय पर विचार करें cat $file 2>&1 /dev/null, या यदि यह केवल बैश है, तो cat $file &> /dev/null
बिल्ली

1
इसके अलावा, $fileहर जगह इसे उद्धृत करने पर विचार करें - और कृपया, $(commands ...)इसके बजाय का उपयोग करें `backticks`...
बिल्ली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.