उनकी सामग्री में 100% एनयूएल वर्ण वाली फाइलें कैसे खोजें?


16

लिनक्स कमांड-लाइन कमांड क्या है जो ऐसी फाइलों की पहचान कर सकता है?

AFAIK findकमांड (या grep) केवल टेक्स्ट फ़ाइल के अंदर एक विशिष्ट स्ट्रिंग से मेल खा सकती है । लेकिन मैं पूरी सामग्री से मेल खाना चाहता हूं, यानी मैं देखना चाहता हूं कि कौन सी फाइलें नियमित अभिव्यक्ति से मेल खाती हैं \0+, लाइन अंत चरित्र (ओं) की अनदेखी । शायद find . cat | grepमुहावरा काम कर सकता है, लेकिन मैं नहीं जानता कि कैसे grep की अनदेखी लाइनों (और द्विआधारी के रूप में फ़ाइल का इलाज) बनाने के लिए।

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


आप इसमें संख्यात्मक शून्य होने वाली फ़ाइलों का मतलब है?
राहुल पाटिल

2
मुझे लगता है कि यह संख्यात्मक शून्य के बजाय NULL वर्णों के बारे में है।
gertvdijk

10
यहाँ एक कदम वापस लेते हैं। हर कुछ दिनों में, जब आपका लैपटॉप फ्रीज हो जाता है? क्यों हम ठीक करने की कोशिश नहीं कर रहे हैं कि यहां, वास्तविक समस्या?
D_Bye

2
@D_Bye यह अच्छा विचार है, लेकिन अभी तक यह बहुत दूर नहीं आया था: [ unix.stackexchange.com/questions/57894/…
एडम

1
क्या आपने -vgrep के विकल्प पर विचार किया है : उन सभी फाइलों को फ़िल्टर करें जिनकी कोई बाइट 1 से 255 है।
ctrl-alt-delor

जवाबों:


10

आप grepपर्ल रेगेक्स मोड का उपयोग करके ␀ वर्णों के लिए कर सकते हैं :

$ echo -ne "\0\0" > nul.bin
$ echo -ne "\0x\0" > non-nul.bin
$ grep -P "[^\0]" *.bin
Binary file non-nul.bin matches

तो आप इसका उपयोग कर सकते हैं:

for path in *.foo
do
    grep -P "[^\0]" "$path" || echo "$path"
done

मुझे अनपेक्षित परिणाम मिलते हैं, का उपयोग करते हुए GNU grep 2.5.4। भले ही मैं उपयोग करता हूं --binary-files=textया --binary-files=binary, यह trueसभी गैर-रिक्त डेटा मानों के लिए एक परिणाम देता है , उदाहरण के लिए। "\0\0", "\0x\0", "abcd"... सटीक कोड मैं प्रयोग किया जाता है: for typ in binary text ;do for dat in '\0\0' '\0x\0' 'abcd' '' ;do printf "$dat" >f; grep --binary-files=$typ -P '[^\0]' f >/dev/null && echo true || echo false; done; done
Peter.O

1
मैंने अब और कोशिश की है GNU grep) 2.10। यह बाद का संस्करण अपेक्षित परिणाम देता है ... इसलिए, एक
पेटी

1
किसी फ़ाइल पर printf '\0\n\0\0\n\n' > fileया printf '\n' > fileउस मामलों के लिए बनाई गई विफल हो जाती है।
स्टीफन चेजलस

2
@ स्टीफनचेलजस ओपी ने कहा "लाइन एंड कैरेक्टर को नजरअंदाज करना।" तो किसी भी फ़ाइल में केवल \0और \nवर्ण होते हैं (या तो शून्य भी) एक मैच होगा।
lbb0

6

मैं इस बात से सहमत हूं कि D_Bye समस्या की जड़ को खोजने के बारे में क्या कहता है।

वैसे भी यह जाँचने के लिए कि क्या किसी फ़ाइल में केवल \0और / या \nआप उपयोग कर सकते हैं tr:

<file tr -d '\0\n' | wc -c

जो शून्य / न्यूलाइन और खाली फ़ाइलों के लिए 0 देता है।


2
tr -d '\0\n'न्यूलाइन इश्यू को हल करता है, जो तब केवल आउटपुट में लिस्ट की जा रही खाली फाइलों के इश्यू (?) को छोड़ता है ... यह हर फाइल की हर बाइट को प्रोसेस करता है (हालांकि यह इश्यू हो सकता है या नहीं भी) +1
पीटरो

@ पीटर.ओ: मैंने न्यूलाइन की आवश्यकता को याद किया, धन्यवाद। यह समाधान बहुत अनुकूलित नहीं है और यदि यह बहुत सारे डेटा पर चलना है तो यह एक समाधान के साथ बेहतर होगा जो गैर-मिलान वाले बाइट्स को खोजने पर आगे बढ़ता है।
Thor

ये अच्छी तरह काम करता है। मुझे मेरा मामला है कि मुझे केवल शून्य-लंबाई फ़ाइलों को बाहर करना सुनिश्चित करना था। धन्यवाद।
एडम रिक्ज़ोस्की

1
हालांकि, यह "खाली" होने के रूप में नई सुर्खियों वाली फाइलों को भी गिनाएगा।
क्रिस डाउन

1
@ क्रिसडाउन: मैंने उत्तर पाठ को स्पष्ट कर दिया कि यह क्या करता है। यह स्पष्ट नहीं है कि ओपी न्यूलाइन-ओनली फ़ाइलों के साथ क्या करना चाहता है।
थोर

5

मुझे संदेह है कि वे फाइलें विरल हैं, अर्थात उनके पास कोई डिस्क स्थान आवंटित नहीं है, वे सिर्फ एक फ़ाइल का आकार निर्दिष्ट करते हैं ( duउनके लिए 0 रिपोर्ट करेंगे)।

जिस स्थिति में, GNU खोज के साथ, आप कर सकते हैं (कोई फ़ाइल पथ नहीं मानकर नई वर्ण शामिल हैं):

find . -type f -size +0 -printf '%b:%p\n' | grep '^0:' | cut -d: -f2-

अच्छी बात। मैंने इसके बारे में कभी सोचा नहीं। मै कोशिश करुॅगा। उपयोग करने duसे फ़ाइल सिस्टम में हर एक फ़ाइल की सामग्री को खरोंचने से रोका जा सकेगा, इसलिए पूरी प्रक्रिया को पूरा करने में 30+ मिनट नहीं लगेंगे।
एडम रिक्ज़ोस्की

(और printf %bउपरोक्त रिपोर्ट क्या duरिपोर्ट करेगी)
स्टीफन चेज़लस

मैं बदल जाएगा -size +0करने के लिए -size +1तो शून्य लम्बाई फ़ाइलों परिणामों से बाहर रखा गया है। साथ ही \nउनके रास्ते में मौजूद फाइलें इस कमांड के लिए समस्या पैदा करेंगी।
टायसन

@ टायसन -size +00. से अधिक के आकार के लिए कड़ाई से है। -size +1512 से अधिक के आकार के लिए कड़ाई से होगा। न्यूलाइन सीमा का पहले ही उल्लेख किया गया था।
स्टीफन चेजालस

@ StéphaneChazelas मेरे बारे में बताने के लिए धन्यवाद -size +1, आप वास्तव में सही हैं। मैंने अपना उत्तर तय कर लिया है । :-)
टायसन

4

यहां एक छोटा अजगर कार्यक्रम है जो यह कर सकता है:

import sys

def only_contains_nulls(fobj, chunk_size=1024):
    first = True
    while True:
        data = fobj.read(chunk_size)
        if not data:
            if first:
                return 1  # No data
            else:
                return 0
        if data.strip("\0"):
            return 1
        first = False

if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        sys.exit(only_contains_nulls(f))

और कार्रवाई में:

$ printf '\0\0\0' > file
$ ./onlynulls file && echo "Only nulls" || echo "Non-null characters"
Only nulls
$ printf a >> file
$ ./onlynulls file && echo "Only nulls" || echo "Non-null characters"
Non-null characters

यदि आप पाते हैं का उपयोग करके एक से अधिक फ़ाइलों की जाँच कर सकते -exec, xargs, जीएनयू parallel, और इसी तरह के कार्यक्रमों। वैकल्पिक रूप से, यह उन फ़ाइलनामों को प्रिंट करेगा, जिनसे निपटने की आवश्यकता है:

files=( file1 file2 )
for file in "${files[@]}"; do
    ./onlynulls "$file" || printf '%s\n' "$file"
done

इस बात को ध्यान में रखें कि यदि आप इसका उत्पादन किसी अन्य प्रोग्राम में करने जा रहे हैं, तो फ़ाइल नाम में नई सुर्खियाँ हो सकती हैं, इसलिए आपको इसे अलग तरीके से (उपयुक्त रूप से, साथ \0) परिसीमित करना चाहिए ।

यदि आपके पास बहुत सारी फाइलें हैं, तो समानांतर प्रसंस्करण के लिए एक विकल्प का उपयोग करना बेहतर होगा, क्योंकि यह केवल एक बार में एक फ़ाइल पढ़ता है।


2
खबरदार, शून्य लम्बाई फ़ाइलें (जैसे: /etc/nologin, ~/.hushlogin, .nomedia, ...) इस उत्तर से गलत पहचान की जाती है।
टायसन

@ टायसन ने इशारा किया कि धन्यवाद! मैंने अभी इसे ठीक किया है।
क्रिस डाउन

3

ऐसी फाइलें खोजें जिनमें केवल null-char '\ 0' और newline chars '\ n' हों। में sed कारणों प्रत्येक फ़ाइल एक लाइन में किसी भी गैर-शून्य चरित्र खोजने पर तुरंत छोड़ने की खोज करते हैं।
q

find -type f -name 'file-*' |
  while IFS= read -r file ;do 
      out=$(sed -n '1=; /^\x00\+$/d; i non-null
                      ; q' "$file")
      [[ $out == "1" ]] &&  echo "$file"
  done

परीक्षण फाइलें बनाएं

> file-empty
printf '%s\n' 'line1' 'line2' 'line3'      > file-with-text           
printf '%4s\n' '' '' xx | sed 's/ /\x00/g' > file-with-text-and-nulls
printf '%4s\n' '' '' '' | sed 's/ /\x00/g' > file-with-nulls-and-newlines
printf '%4s'   '' '' '' | sed 's/ /\x00/g' > file-with-nulls-only

उत्पादन

./file-with-nulls-and-newlines
./file-with-nulls-only

या तो -print0तर्क से गायब लगता है findया IFS=भाग गड़बड़ है। इरादा परिसीमन क्या था?
टायसन

3

यह एक-लाइनर का उपयोग कर जीएनयू 100% नुल फ़ाइलों को खोजने के लिए सबसे कारगर तरीका है find, xargsऔर grep(बाद यह सोचते हैं PCRE समर्थन के साथ बनाया गया है):

find . -type f -size +0 -readable -print0 |
  LC_ALL=C xargs -r0 grep -LP "[^\x00]" --

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

  • गैर-विरल फाइलें खोज में शामिल हैं।
  • गैर-पठनीय फ़ाइलों को Permission deniedचेतावनी से बचने के लिए grep को पारित नहीं किया जाता है ।
  • grepकिसी भी गैर-बाइट बाइट को खोजने के बाद फाइलों से डेटा पढ़ना बंद कर देगा ( LC_ALL=Cयह सुनिश्चित करने के लिए उपयोग किया जाता है कि प्रत्येक बाइट को एक चरित्र के रूप में व्याख्या किया गया है )।
  • रिक्त फ़ाइलें (शून्य बाइट्स) परिणामों में शामिल नहीं हैं।
  • कम grepप्रक्रिया कुशलतापूर्वक कई फाइलों की जांच करती है।
  • नए सिरे से युक्त या शुरू होने वाले रास्तों को -सही तरीके से संभाला जाता है।
  • पायथन / पर्ल की कमी वाले अधिकांश एम्बेडेड सिस्टम पर काम करता है।

पासिंग -Zके लिए विकल्प grepका उपयोग xargs -r0 ...की अनुमति देता है आगे क्रियाओं 100% नुल फ़ाइलों पर किया जा करने के लिए (जैसे: सफाई):

find . -type f -size +0 -readable -print0 |
  LC_ALL=C xargs -0 grep -ZLP "[^\x00]" -- |
  xargs -r0 rm --

मैं सिम्बलिंक का पालन करने से बचने के लिए findविकल्पों का उपयोग करने की भी सलाह देता हूं -P, और -xdevफाइलसिस्टम को ट्रेस करने से बचने के लिए (उदाहरण के लिए: दूरस्थ आरोहण, उपकरण के पेड़, बाइंड माउंट, आदि)।

के लिए लाइन अंत चरित्र (रों) अनदेखी , निम्नलिखित संस्करण (हालांकि मुझे नहीं लगता कि इस तरह के एक अच्छा विचार है है) काम करना चाहिए:

find . -type f -size +0 -readable -print0 |
  LC_ALL=C xargs -r0 grep -LP "[^\x00\r\n]" --

उन सभी को एक साथ रखना, जिनमें अवांछित फ़ाइलों को हटाने (100% nul / newline वर्ण) शामिल हैं, ताकि उन्हें बैकअप होने से रोका जा सके:

find -P . -xdev -type f -size +0 -readable -print0 |
  LC_ALL=C xargs -0 grep -ZLP "[^\x00\r\n]" -- |
  xargs -0 rm --

मैं खाली फ़ाइलों (शून्य बाइट्स) सहित अनुशंसा नहीं करता, वे अक्सर बहुत विशिष्ट उद्देश्यों के लिए मौजूद होते हैं ।


इतने सारे विकल्पों में से सबसे तेज़ होना एक साहसिक दावा है। यदि आप एक बेंचमार्क जोड़ते हैं, तो मैं आपके उत्तर को चिह्नित कर दूंगा:
एडम रिक्जेकोस्की

ऐसा मानदंड कई कारकों पर निर्भर करेगा, जिसमें विभिन्न डिस्क सबसिस्टम का प्रदर्शन शामिल है।
टायसन

बेशक, लेकिन कुछ भी नहीं से बेहतर है। विभिन्न दृष्टिकोण सीपीयू उपयोग को अलग तरीके से अनुकूलित करते हैं, इसलिए यह एसएसडी पर या यहां तक ​​कि कैश्ड फ़ाइलों पर बेंचमार्क करने के लिए समझ में आता है। वर्तमान में आप जिस मशीन पर काम कर रहे हैं, उसे लें, एक वाक्य लिखें कि यह क्या है (सीपीयू प्रकार, कोर, रैम, हार्ड ड्राइव प्रकार), फ़ाइल सेट का वर्णन करें (जैसे कर्नेल स्रोत क्लोन + 1 जीबी फ़ाइल \0जिसमें 900 एमबी छेद भरा हो) और परिणामों का वर्तमान समय। यदि आप इसे एक तरह से बेंचमार्क के लिए आश्वस्त कर रहे हैं, तो यह सबसे अधिक संभावना है कि हम सभी के लिए आश्वस्त हो जाएगा
एडम

"अधिकांश एम्बेडेड सिस्टम" में GNU उपयोगिताओं नहीं है। अधिक संभावना व्यस्त वाले।
स्टीफन चेजालस

-Pमें डिफ़ॉल्ट है find। यदि आप सिमिलिंक का पालन करना चाहते हैं, तो यह -L/ है -follow। आप पाएंगे कि POSIX उस विकल्प के लिए भी निर्दिष्ट नहीं करता है find(भले ही POSIX वह है जिसने कुछ कमांड के लिए उन -P / -H / -L को पेश किया है)।
स्टीफन चेज़लस

0

GNU sed का उपयोग करने के लिए आप -zविकल्प का उपयोग कर सकते हैं , जो एक पंक्ति को शून्य-टर्मिनेटेड स्ट्रिंग्स के रूप में परिभाषित करता है और इसके लिए रिक्त विकल्प को हटाता है जैसे:

if [ "$( sed -z '/^$/d' "$file" | head -c 1 | wc -c )" -eq 0 ]; then
    echo "$file contains only NULL!"
fi

हेड कमांड इनबेटीन सिर्फ एक अनुकूलन है।


-1

अजगर

एक दस्तावेज

उपनाम को परिभाषित करें:

alias is_binary="python -c 'import sys; sys.exit(not b\"\x00\" in open(sys.argv[1], \"rb\").read())'"

झसे आज़माओ:

$ is_binary /etc/hosts; echo $?
1
$ is_binary `which which`; echo $?
0

कई फाइलें

सभी बाइनरी फ़ाइलों को पुनरावर्ती रूप से ढूंढें:

IS_BINARY='import sys; sys.exit(not b"\x00" in open(sys.argv[1], "rb").read())'
find . -type f -exec bash -c "python -c '$IS_BINARY' {} && echo {}" \;

सभी गैर-बाइनरी फ़ाइलों को खोजने के लिए, के &&साथ बदलें ||


1
केवल nul वर्ण (newlines की अनदेखी) वाली फ़ाइलों की पहचान करने के लिए कहा गया प्रश्न , यहाँ दिया गया पायथन कोड किसी भी nul वर्ण वाली फ़ाइलों की पहचान करता है ।
टायसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.