मैं इस 'find' कमांड को कैसे चला सकता हूं, लेकिन केवल गैर-बाइनरी फाइलों पर?


8

मैं एक पुनरावर्ती निर्देशिका पदानुक्रम में सभी फ़ाइलों से अनुगामी व्हाट्सएप को निकालना चाहता हूं। मैं इसका उपयोग करता हूं:

find * -type f -exec sed 's/[ \t]*$//' -i {} \;

यह काम करता है, लेकिन पाए जाने वाले बाइनरी फाइलों से "व्हाट्सएप" को भी हटा देगा, जो अवांछनीय है।

मैं findबाइनरी फ़ाइलों पर इस कमांड को चलाने से बचने के लिए कैसे कहूं ?


यूनिक्स फाइल सिस्टम "बाइनरी" और "नॉन-बाइनरी" फाइलों के बीच कोई अंतर नहीं करता है; फ़ाइल के अंदर किस तरह का डेटा है, यह बताने का कोई तरीका नहीं है।
Wooble

@Wooble: यह सही है, लेकिन ऐसे कमांड हैं fileजो डेटा का निरीक्षण कर सकते हैं।
जॉन फेमिनाला

जवाबों:


4

आप fileउन फ़ाइलों की पहचान करने में मदद करने के लिए यूनिक्स कमांड का उपयोग करने की कोशिश कर सकते हैं जो आप नहीं चाहते हैं, लेकिन मुझे लगता है कि यह बेहतर हो सकता है यदि आप स्पष्ट रूप से निर्दिष्ट करते हैं कि आप उन फाइलों के बजाय जो आप नहीं मारना चाहते हैं।

find * -type f \( -name \*.java -o -name \*.c -o -name \*.sql \) -exec sed 's/[ \t]*$//' -i {} \;

स्रोत नियंत्रण फ़ाइलों में ट्रैवर्सिंग से बचने के लिए आप कुछ ऐसा चाहते हैं

find * \! \( -name .svn -prune \) -type f \( -name \*.java -o -name \*.c -o -name \*.sql \) -exec sed 's/[ \t]*$//' -i {} \;

आपको अपने शेल के आधार पर कुछ बैकस्लैश की आवश्यकता हो सकती है या नहीं भी हो सकती है।


2
मैं आपके बारे में नहीं जानता, लेकिन हमारी सभी जावा स्रोत फाइलें हमेशा मानक UTF-8 में होती हैं, ताकि sed कमांड हमेशा उन सभी के साथ सही काम न करे। मैं भी एक -iविकल्प के बिना sed करने के लिए सिस्टम है । पोर्टेबल शेल कमांड लिखना मुश्किल है, है ना?
tchrist

4

इसे कमांड लाइन पर किया जा सकता है।

$ find . -type f -print|xargs file|grep ASCII|cut -d: -f1|xargs sed 's/[ \t]*$//' -i

3

इसे चलाने के लिए सबसे सरल और सबसे पोर्टेबल उत्तर है:

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
    next unless -f && -T;
    system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;

मैं समझाता हूं कि नीचे क्यों, जहां मैं यह भी बताता हूं कि यह केवल कमांड लाइन का उपयोग करके कैसे किया जाता है, साथ ही साथ ट्रांस-एएससीआईआई टेक्स्टफाइल्स जैसे कि आईएसओ-8859-1 (लैटिन -1) और यूटीएफ -8 के साथ कैसे व्यवहार किया जाए, जो कि गैर है -एएससीआई व्हाट्सएप उनमें।


बाकी की कहानी

समस्या यह है कि खोज (1) न तो -Tफ़िल्टरेस्ट ऑपरेटर का समर्थन करता है , और न ही यह एन्कोडिंग को पहचानता है यदि ऐसा किया है - जिसे आपको UTF-8, वास्तविक मानक यूनिकोड एन्कोडिंग का पता लगाने की आवश्यकता है।

आप जो कुछ भी कर सकते हैं वह फाइलनाम सूची को एक परत के माध्यम से चलाने के लिए है जो बाइनरी फ़ाइलों को बाहर फेंकती है। उदाहरण के लिए

$ find . -type f | perl -nle 'print if -T' | xargs sed -i 's/[ \t]*$//'

हालाँकि अब आपको अपने फाइलनामों में व्हाट्सएप से परेशानी है, इसलिए आपको इसे समाप्त करने की आवश्यकता है:

$ find . -type f -print0 | perl -0 -nle 'print if -T' | xargs -0 sed -i 's/[ \t]*$//'

एक और चीज जो आप कर सकते हैं वह है , findलेकिन इसका उपयोग नहीं है find2perl, क्योंकि पर्ल -Tपहले से ही समझता है :

$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl

और अगर आप चाहते हैं कि पर्ल को इसकी फाइलें UTF-8 में हों, तो उपयोग करें

$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl -CSD

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

हालाँकि, यदि आप वह सब करने जा रहे हैं, तो आप पूरी तरह से sed (1) छोड़ सकते हैं। एक बात के लिए, यह अधिक पोर्टेबल है, क्योंकि POSIX संस्करण सेड (1) समझ में नहीं आता है -i, जबकि पर्ल के सभी संस्करण करते हैं। की Latterday संस्करणों sed प्यार से बहुत उपयोगी विनियोजित -iपर्ल जहां ti पहले प्रकट होता है से विकल्प।

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

 s/[ \t]*$//

होना चाहिए

 s/[ \t]+$//

हालांकि, यह समझने के लिए कि कैसे एक गैर-पॉसिक्स एक्सटेंशन की आवश्यकता होती है , सीड (1) प्राप्त करें, आमतौर पर या तो -Rसिस्टम के लिए होता है जैसे सोलारिस या लिनक्स, या -Eओपनबीएसडी या मैकओएस जैसे बीएसडी वाले। मुझे संदेह है कि यह AIX के तहत असंभव है। पोर्टेबल शेल स्क्रिप्ट की तुलना में पोर्टेबल शेल लिखना आसान है, आप जानते हैं।

0xA0 पर चेतावनी

हालांकि वे ASCII में केवल क्षैतिज सफेद अंतरिक्ष वर्ण हैं, दोनों ISO-8859-1 और परिणामस्वरूप यूनिकोड में कोड बिंदु U + 00A0 पर NO-BREAK स्पेस भी है। यह कई यूनिकोड कॉर्पोरा में पाए जाने वाले शीर्ष दो गैर-एएससीआईआई पात्रों में से एक है, और मैंने हाल ही में बहुत सारे लोगों के रेगेक्स कोड को देखा है क्योंकि वे इसके बारे में भूल गए थे।

तो आप ऐसा क्यों नहीं करते:

$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -i -pe 's/[\t\xA0 ]+$//'

आप UTF-8 के साथ ऐड निपटने के लिए फ़ाइलों को हो सकता है तो -CSD, और आप पर्ल v5.10 या अधिक से अधिक चल रहे हैं, तो आप उपयोग कर सकते हैं \hक्षैतिज खाली स्थान के लिए और \Rएक सामान्य LINEBREAK, जिसमें शामिल है के लिए \r, \n, \r\n, \f, \cK, \x{2028}, और \x{2029}:

$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -CSD -i -pe 's/\h+(?=\R*$)//'

यह सभी यूटीएफ -8 फाइलों पर काम करेगा, चाहे उनकी लाइनब्रेक, HorizSpaceप्रत्येक लाइन के अंत में यूनिकोड लाइनब्रेक (CRLF कॉम्ब्स शामिल करें) से पहले pesky NO-BREAK स्पेस सहित क्षैतिज व्हाट्सएप (यूनिकोड कैरेक्टर प्रॉपर्टी ) को हटाने से छुटकारा न मिले ।

यह sed (1) संस्करण की तुलना में बहुत अधिक पोर्टेबल है , क्योंकि केवल एक पर्ल (1) कार्यान्वयन है, लेकिन कई sed (1)।

मुख्य समस्या जो मुझे दिखाई देती है, वह ढूंढने (1) के साथ है, क्योंकि कुछ सचमुच पुनर्गणना प्रणालियों पर (आप जानते हैं कि आप कौन हैं, AIX और सोलारिस), यह सुपरक्रिटिकल -print0निर्देश को नहीं समझेगा । यदि यह आपकी स्थिति है, तो आपको बस File::Findपर्ल से सीधे मॉड्यूल का उपयोग करना चाहिए , और कोई अन्य यूनिक्स उपयोगिताओं का उपयोग नहीं करना चाहिए । यहाँ आपके कोड का एक शुद्ध पर्ल संस्करण है जो किसी और चीज़ पर भरोसा नहीं करता है:

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
     next unless -f && -T;
     system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);  
} => @dirs;

यदि आप ASCII या ISO-8859-1 टेक्स्टफाइल्स पर चल रहे हैं, तो यह ठीक है, लेकिन यदि आप ASCII या UTF-8 फ़ाइलों के साथ चल रहे हैं, -CSDतो आंतरिक कॉल में स्विच को पर्ल में जोड़ें।

यदि आपके पास ASCII, ISO-8859-1, और UTF-8, तीनों के मिश्रित एनकोडिंग हैं, तो मुझे डर है कि आपको एक और समस्या है। :( आपको प्रति-फ़ाइल के आधार पर एन्कोडिंग का पता लगाना होगा, और ऐसा अनुमान लगाने का एक अच्छा तरीका नहीं है।

यूनिकोड व्हाट्सएप

रिकॉर्ड के लिए, यूनिकोड में 26 अलग-अलग व्हाट्सएप चरित्र हैं। आप इन को सूँघने के लिए यूनीचर्स यूटिलिटी का उपयोग कर सकते हैं । केवल पहले तीन क्षैतिज व्हाट्सएप चार्ट लगभग कभी देखे गए हैं:

$ unichars '\h'
 ---- U+0009 CHARACTER TABULATION
 ---- U+0020 SPACE
 ---- U+00A0 NO-BREAK SPACE
 ---- U+1680 OGHAM SPACE MARK
 ---- U+180E MONGOLIAN VOWEL SEPARATOR
 ---- U+2000 EN QUAD
 ---- U+2001 EM QUAD
 ---- U+2002 EN SPACE
 ---- U+2003 EM SPACE
 ---- U+2004 THREE-PER-EM SPACE
 ---- U+2005 FOUR-PER-EM SPACE
 ---- U+2006 SIX-PER-EM SPACE
 ---- U+2007 FIGURE SPACE
 ---- U+2008 PUNCTUATION SPACE
 ---- U+2009 THIN SPACE
 ---- U+200A HAIR SPACE
 ---- U+202F NARROW NO-BREAK SPACE
 ---- U+205F MEDIUM MATHEMATICAL SPACE
 ---- U+3000 IDEOGRAPHIC SPACE

$ unichars '\v'
 ---- U+000A LINE FEED (LF)
 ---- U+000B LINE TABULATION
 ---- U+000C FORM FEED (FF)
 ---- U+000D CARRIAGE RETURN (CR)
 ---- U+0085 NEXT LINE (NEL)
 ---- U+2028 LINE SEPARATOR
 ---- U+2029 PARAGRAPH SEPARATOR

0

GNU grep यह पहचानने में बहुत अच्छा है कि कोई फाइल बाइनरी है या नहीं। Solaris के अलावा मुझे यकीन है कि ऐसे अन्य प्लेटफ़ॉर्म हैं जो डिफ़ॉल्ट रूप से स्थापित GNU grep के साथ नहीं आते हैं, लेकिन Solaris की तरह मुझे यकीन है कि आप इसे स्थापित कर सकते हैं।

perl -pi -e 's{[ \t]+$}{}g' `grep -lRIP '[ \t]+$' .`

यदि आप सोलारिस में हैं, तो आप के grepसाथ बदल देंगे /opt/csw/bin/ggrep

grepझंडे निम्न कार्य करें: l, मिलान फ़ाइलों के लिए केवल सूचियों फ़ाइल नाम Rपुनरावर्ती है, I(बाइनरी फ़ाइलों पर ध्यान नहीं देता) केवल पाठ फ़ाइलों से मेल खाता है, और Pपर्ल संगत नियमित अभिव्यक्ति वाक्य रचना के लिए है।

पर्ल भाग फ़ाइल को इन-प्लेस में संशोधित करता है, जो सभी अनुगामी स्थानों / टैब को हटाता है।

अन्त में: यदि UTF8 एक मुद्दा है, तो मेरे साथ युग्मित tchrist का उत्तर पर्याप्त होना चाहिए, बशर्ते grepआप का निर्माण UTF8 समर्थन के साथ बनाया गया हो (आमतौर पर पैकेज अनुरक्षक उस तरह की कार्यक्षमता प्रदान करने का प्रयास करते हैं, हालांकि)।

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