क्यों * नहीं * पार्स `एलएस` (और इसके बजाय क्या करना है)?


204

मैं लगातार इस लिंक को निश्चित रूप से बताते हुए उत्तर देता हूं "डोंट पार्से ls!" यह मुझे कुछ कारणों से परेशान करता है:

  1. ऐसा लगता है कि इस लिंक में जानकारी को छोटे प्रश्न के साथ थोक स्वीकार किया गया है, हालांकि मैं आकस्मिक पढ़ने में कम से कम कुछ त्रुटियां उठा सकता हूं।

  2. यह भी लगता है जैसे कि लिंक में बताई गई समस्याओं ने समाधान खोजने की कोई इच्छा नहीं जगाई है।

पहले पैराग्राफ से:

... जब आप [ls]फ़ाइलों की एक सूची के लिए पूछते हैं , तो एक बहुत बड़ी समस्या है: यूनिक्स व्हाट्सएप, न्यूलाइन्स, कॉमा, पाइप प्रतीकों सहित फ़ाइल नाम में लगभग किसी भी चरित्र की अनुमति देता है, और बहुत कुछ और जो आप कभी भी उपयोग करने की कोशिश करेंगे! NUL को छोड़कर परिसीमन। ... नए lsनामों के साथ फाइलनेम को अलग करता है। यह तब तक ठीक है जब तक कि आपके पास इसके नाम की नई लाइन वाली फाइल न हो। और जब से मुझे इसके किसी भी कार्यान्वयन के बारे में पता नहीं है, lsतो आप नए नामों के बजाय NUL वर्णों के साथ फ़ाइल नाम समाप्त करने की अनुमति देते हैं, इससे हमें सुरक्षित रूप से फ़ाइल नाम की सूची प्राप्त करने में असमर्थ छोड़ देता है ls

बुमेर, है ना? कभी भी हम डेटा के लिए एक नई पंक्तिबद्ध सूचीबद्ध डेटासेट को कैसे संभाल सकते हैं जिसमें न्यूलाइन्स हो सकती हैं? ठीक है, अगर इस वेबसाइट पर सवालों के जवाब देने वाले लोग इस तरह का काम दैनिक आधार पर नहीं करते हैं, तो मैं सोच सकता हूं कि हम कुछ परेशानी में थे।

हालांकि सच्चाई यह है कि अधिकांश lsकार्यान्वयन वास्तव में अपने उत्पादन को पार्स करने के लिए एक बहुत ही सरल एपीआई प्रदान करते हैं और हम सब इसे साकार करने के बिना भी कर रहे हैं। न केवल आप नल के साथ एक फ़ाइल नाम को समाप्त कर सकते हैं, आप एक नल के साथ या किसी अन्य मनमाने ढंग से स्ट्रिंग के साथ शुरू कर सकते हैं जिसे आप चाहें। क्या अधिक है, आप इन मनमाने तार प्रति फ़ाइल-प्रकार असाइन कर सकते हैं । कृपया ध्यान रखें:

LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@

इसे और देखें

अब यह इस लेख का अगला भाग है जो वास्तव में मुझे हालांकि प्राप्त होता है:

$ ls -l
total 8
-rw-r-----  1 lhunath  lhunath  19 Mar 27 10:47 a
-rw-r-----  1 lhunath  lhunath   0 Mar 27 10:47 a?newline
-rw-r-----  1 lhunath  lhunath   0 Mar 27 10:47 a space

समस्या यह है कि आउटपुट से ls, न तो आप या कंप्यूटर बता सकते हैं कि इसके कुछ हिस्सों का नाम क्या है। क्या यह प्रत्येक शब्द है? क्या यह प्रत्येक पंक्ति है? नहीं, इस प्रश्न के अलावा कोई सही उत्तर नहीं है: आप नहीं बता सकते।

यह भी ध्यान दें कि lsकभी-कभी आपके फ़ाइलनाम डेटा को कैसे हटाया जाता है (हमारे मामले में, इसने "a" और "newline"\n शब्दों के बीच के चरित्र को एक प्रश्न चिह्न में बदल दिया ... ?

...

यदि आप वर्तमान निर्देशिका की सभी फाइलों पर चलना चाहते हैं, तो एक forलूप और एक ग्लोब का उपयोग करें :

for f in *; do
    [[ -e $f ]] || continue
    ...
done

जब इसे शेल ग्लब्स वाले फ़ाइलनामों की सूची लौटाती है, तो लेखक इसे फ़ाइल नाम कीls सूची देता है और फिर फ़ाइल सूची प्राप्त करने के लिए शेल ग्लोब का उपयोग करने की सलाह देता है!

निम्नलिखित को धयान मे रखते हुए:

printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
    . /dev/stdin
ls -1q

f i l e n a m e  
file?name

IFS="
" ; printf "'%s'\n" $(ls -1q)

'f i l e n a m e'
'file
name'

POSIX परिभाषित करता है -1और -q lsसंचालन करता है :

-q- गैर-मुद्रण योग्य फ़ाइल नाम वर्णों के प्रत्येक उदाहरण को मजबूर करें और <tab>प्रश्न-चिह्न ( '?') वर्ण के रूप में लिखा जाए । यदि टर्मिनल डिवाइस के लिए आउटपुट है तो कार्यान्वयन डिफ़ॉल्ट रूप से यह विकल्प प्रदान कर सकता है।

-1- (सांख्यिक अंक एक।) प्रति पंक्ति एक प्रविष्टि होने के लिए बल आउटपुट।

- ग्लोबिंग अपनी ही समस्याओं के बिना नहीं है ?मैचों किसी भी चरित्र तो बहु मिलान ?एक सूची में परिणाम एक ही फाइल कई बार मेल खाएगी। वह आसानी से निपट जाता है।

हालांकि यह कैसे करना है यह बात नहीं है - यह सब करने के बाद बहुत कुछ नहीं करता है और नीचे प्रदर्शित किया जाता है - मुझे इसमें दिलचस्पी नहीं थी । जैसा कि मैं इस पर विचार करता हूं, उस प्रश्न का सबसे अच्छा उत्तर स्वीकार किया गया है। मैं आप लोगों को क्या वे कह पर अधिक बार ध्यान केंद्रित करने की कोशिश सुझाव है कि कर सकते हैं कि वे क्या पर से कर नहीं कर सकते। आप बहुत कम संभावना रखते हैं, जैसा कि मुझे लगता है, कम से कम गलत साबित होने के लिए।

लेकिन कोशिश भी क्यों? निश्चित रूप से, मेरी प्राथमिक प्रेरणा यह थी कि दूसरे मुझे बताते रहे कि मैं नहीं कर सकता। मैं अच्छी तरह से जानता हूं कि lsआउटपुट उतना ही नियमित और अनुमानित है जितना आप इसे चाह सकते हैं, जब तक आप जानते हैं कि आपको क्या देखना है। गलत सूचना मुझे सबसे ज्यादा परेशान करती है।

हालांकि, सच्चाई यह है कि पैट्रिक और वम्पस दोनों के उल्लेखनीय अपवाद के साथ। वुम्बी के उत्तर (उत्तरार्द्ध के भयानक संभाल के बावजूद) , मैं यहां के जवाबों में अधिकांश जानकारी को ज्यादातर सही मानता हूं - एक शेल ग्लोब दोनों का उपयोग करना अधिक सरल है और आम तौर पर तब और अधिक प्रभावी होता है जब यह वर्तमान निर्देशिका को खोजने से आता है ls। वे मेरे संबंध में कम से कम, पर्याप्त कारण या तो गलत सूचना से ऊपर लेख में उद्धृत प्रचार और न ही वे स्वीकार्य औचित्य को सही ठहराने के लिए कर रहे हैं नहीं कर रहे हैं, हालांकि, " पार्स कभी नहीं ls "

कृपया ध्यान दें कि पैट्रिक जवाब के असंगत परिणाम ज्यादातर का उपयोग कर उसे का परिणाम हैं zshतो bashzsh- डिफ़ॉल्ट रूप से - शब्द-विभाजन $(आदेश को )पोर्टेबल तरीके से प्रतिस्थापित नहीं करता है। इसलिए जब वह पूछता है कि बाकी फाइलें कहां गईं ? इस सवाल का जवाब है कि आपका खोल उन्हें खा गया। यही कारण है कि आपको पोर्टेबल शेल कोड SH_WORD_SPLITका उपयोग zshऔर व्यवहार करते समय चर को सेट करने की आवश्यकता होती है । मैं अपने जवाब में इसे भ्रामक रूप से भ्रामक मानते हुए अपनी विफलता को मानता हूं।

Wumpus का जवाब मेरे लिए गणना नहीं करता है - एक सूची संदर्भ में ?चरित्र है एक खोल ग्लोब। मुझे नहीं पता कि कैसे और क्या कहना है।

एक से अधिक परिणाम मामले को संभालने के लिए आपको ग्लोब की लालच को प्रतिबंधित करना होगा। निम्नलिखित केवल भयानक फ़ाइल नामों का एक परीक्षण आधार बनाएगा और इसे आपके लिए प्रदर्शित करेगा:

{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
        s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin

echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}

आउटपुट

`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b

NOW LITERAL - COMMA,SEP
?
 \, ?
     ^, ?
         `, ?
             b, [       \, [
\, ]    ^, ]
^, _    `, _
`, a    b, a
b

FILE COUNT: 12

अब मैं हूँ सुरक्षित हर चरित्र है कि एक नहीं है /slash, -dash, :colon, या अल्फा-न्यूमेरिक एक खोल ग्लोब तो में चरित्र sort -uअद्वितीय परिणामों के लिए सूची। यह सुरक्षित है क्योंकि lsपहले से ही सुरक्षित है-हमारे लिए किसी भी गैर मुद्रण योग्य वर्ण। घड़ी:

for f in $(
        ls -1q |
        sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
        sort -u | {
                echo 'PRE-GLOB:' >&2
                tee /dev/fd/2
                printf '\nPOST-GLOB:\n' >&2
        }
) ; do
        printf "FILE #$((i=i+1)): '%s'\n" "$f"
done

उत्पादन:

PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b

POST-GLOB:
FILE #1: '?
           \'
FILE #2: '?
           ^'
FILE #3: '?
           `'
FILE #4: '[     \'
FILE #5: '[
\'
FILE #6: ']     ^'
FILE #7: ']
^'
FILE #8: '_     `'
FILE #9: '_
`'
FILE #10: '?
            b'
FILE #11: 'a    b'
FILE #12: 'a
b'

नीचे मैं समस्या को फिर से बताता हूं लेकिन मैं एक अलग पद्धति का उपयोग करता हूं। याद रखें कि - \0अशक्त के अलावा - /ASCII वर्ण पथनाम में निषिद्ध एकमात्र बाइट है। मैं यहाँ एक तरफ ग्लब्स रखता हूँ और इसके बदले POSIX निर्दिष्ट -dविकल्प और इसके लिए lsPOSIX निर्दिष्ट -exec $cmd {} +निर्माण का संयोजन करता हूँ find। क्योंकि findकेवल स्वाभाविक रूप से कभी भी /अनुक्रम में एक का उत्सर्जन होगा , निम्नलिखित आसानी से हर प्रविष्टि के लिए सभी डेंट्री जानकारी सहित एक पुनरावर्ती और मज़बूती से सीमांकित फ़ेलिस्ट खरीदता है। जरा सोचिए कि आप इस तरह से क्या कर सकते हैं:

#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'

###OUTPUT

152398 drwxr-xr-x 1 1000 1000        72 Jun 24 14:49
.///testls///

152399 -rw-r--r-- 1 1000 1000         0 Jun 24 14:49
.///testls/?
            \///

152402 -rw-r--r-- 1 1000 1000         0 Jun 24 14:49
.///testls/?
            ^///

152405 -rw-r--r-- 1 1000 1000         0 Jun 24 14:49
.///testls/?
        `///
...

ls -i बहुत उपयोगी हो सकता है - खासकर जब परिणाम विशिष्टता प्रश्न में है।

ls -1iq | 
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' | 
tr -d '\n' | 
xargs find

ये सिर्फ सबसे पोर्टेबल साधन हैं जिनके बारे में मैं सोच सकता हूं। GNU के साथ lsआप कर सकते हैं:

ls --quoting-style=WORD

और अंतिम, यहाँ पार्सिंगls का एक बहुत ही सरल तरीका है जो कि जब मैं इनोड नंबरों की आवश्यकता होती है तो अक्सर उपयोग करने के लिए होता है:

ls -1iq | grep -o '^ *[0-9]*'

यह सिर्फ इनोड संख्या देता है - जो कि एक और आसान POSIX निर्दिष्ट विकल्प है।


12
@mikeserv ठीक है मैंने किया। शेल ग्लोब 2.48 गुना तेज है। time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'= 3.18s बनाम time bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'= 1.28s
पैट्रिक

28
अपने सबसे हालिया अपडेट के संबंध में, कृपया दृश्य कोड पर निर्भर होना बंद कर दें कि आपका कोड काम करता है। अपने आउटपुट को एक वास्तविक प्रोग्राम में पास करें और प्रोग्राम को फ़ाइल पर ऑपरेशन करने की कोशिश करें और करें। यही कारण है कि मैं statअपने उत्तर में उपयोग कर रहा था , क्योंकि यह वास्तव में जांचता है कि प्रत्येक फ़ाइल मौजूद है। sedचीज़ के साथ नीचे की ओर आपका बिट काम नहीं करता है।
पैट्रिक

57
आप गंभीर नहीं हो सकते। कैसे अपने सवाल का वर्णन करता है कि सभी हुप्स के माध्यम से कूदना आसान या सरल हो सकता है या किसी भी तरह से बेहतर है lsकि पहले स्थान पर पार्स न करें ? आप जो वर्णन कर रहे हैं वह बहुत कठिन है। मुझे यह सब समझने के लिए इसका पुनर्निर्माण करना होगा और मैं अपेक्षाकृत सक्षम उपयोगकर्ता हूं। आप संभवतः अपने औसत जो से इस तरह के कुछ से निपटने में सक्षम होने की उम्मीद नहीं कर सकते।
terdon

46
-1 किसी तर्क को चुनने के लिए प्रश्न का उपयोग करने के लिए। पार्सिंग lsआउटपुट गलत होने के सभी कारणों को मूल लिंक में अच्छी तरह से कवर किया गया था (और अन्य जगहों पर भी)। अगर ओपी इसे समझने में मदद मांग रहा होता, तो यह सवाल वाजिब होता, लेकिन इसके बजाय ओपी सिर्फ यह साबित करने की कोशिश कर रहा है कि उसका गलत इस्तेमाल ठीक है।
आर ..

14
@mikeserv यह सिर्फ इतना ही नहीं है parsing ls is badfor something in $(command)सटीक परिणाम प्राप्त करने के लिए शब्द-बंटवारे पर करना और भरोसा करना बड़े बहुमत के लिए बुरा है, command'sजिसमें सरल आउटपुट नहीं है।
BroSlow

जवाबों:


184

मैं इसके बारे में बिल्कुल आश्वस्त नहीं हूं, लेकिन चलो तर्क के लिए मान लें जो आप कर सकते हैं , यदि आप पर्याप्त प्रयास में रखने के लिए तैयार हैं, तो lsमज़बूती से आउटपुट को पार्स करें , यहां तक ​​कि "प्रतिकूल" के चेहरे पर - कोई है जो आपके द्वारा लिखे गए कोड को जानता है और इसे तोड़ने के लिए डिज़ाइन किए गए फ़ाइलनाम को जानबूझकर चुन रहा है।

अगर आप ऐसा कर सकते हैं, तब भी यह एक बुरा विचार होगा

बॉर्न शेल एक अच्छी भाषा नहीं है। इसका उपयोग किसी भी जटिल चीज़ के लिए नहीं किया जाना चाहिए, जब तक कि किसी अन्य कारक (जैसे autoconf) की तुलना में चरम पोर्टेबिलिटी अधिक महत्वपूर्ण न हो ।

मेरा दावा है कि यदि आप एक ऐसी समस्या से जूझ रहे हैं, जहाँ आउटपुट का प्रदर्शन lsशेल स्क्रिप्ट के लिए कम से कम प्रतिरोध के मार्ग जैसा लगता है, तो यह एक मजबूत संकेत है कि आप जो भी कर रहे हैं वह शेल के लिए बहुत जटिल है और आपको पूरी चीज़ को फिर से लिखना चाहिए पर्ल या पायथन। यहाँ पायथन में आपका आखिरी कार्यक्रम है:

import os, sys
for subdir, dirs, files in os.walk("."):
    for f in dirs + files:
      ino = os.lstat(os.path.join(subdir, f)).st_ino
      sys.stdout.write("%d %s %s\n" % (ino, subdir, f))

इसका कोई मुद्दा नहीं है कि फ़ाइल नाम में असामान्य वर्णों के साथ - आउटपुट अस्पष्ट है उसी तरह से आउटपुट lsअस्पष्ट है, लेकिन यह "वास्तविक" प्रोग्राम में कोई फर्क नहीं पड़ेगा (जैसा कि इस तरह एक डेमो के विपरीत), जो os.path.join(subdir, f)सीधे परिणाम का उपयोग करें ।

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

import os, sys
filelist = []
for subdir, dirs, files in os.walk("."):
    for f in dirs + files:
        if f[0] == '.' or f[-1] == '~': continue
        lstat = os.lstat(os.path.join(subdir, f))
        filelist.append((f, subdir, lstat.st_ino))

filelist.sort(key = lambda x: x[0])
for f, subdir, ino in filelist: 
   sys.stdout.write("%d %s %s\n" % (ino, subdir, f))

5
यह अच्छा है। क्या वह for in | for inपुनरावृत्ति की बात करता है ? मुझे यकीन नहीं है। भले ही यह एक से अधिक नहीं हो सकता है, है ना? यह एकमात्र उत्तर है जो मुझे अब तक समझ में आता है।
22

10
कोई पुनरावृत्ति, बस नेस्टेड- forलूप। os.walkपर्दे के पीछे से कुछ गंभीर रूप से भारी उठाने की कोशिश कर रहा है, लेकिन आपको इसके बारे में चिंता करने की ज़रूरत नहीं है कि आपको आंतरिक lsया findकाम करने के तरीके के बारे में अधिक चिंता करने की ज़रूरत नहीं है ।
zwol

6
तकनीकी रूप से, जेनरेटर ऑब्जेक्टos.walk लौटाता है । जनरेटर आलसी सूचियों के पायथन संस्करण हैं। हर बार जब बाहरी लूप के लिए इसमें बदलाव होता है, तो जनरेटर लगाया जाता है और दूसरे उपनिर्देशिका की सामग्री को "पैदावार" देता है। पर्ल में समतुल्य कार्यक्षमता है , अगर यह मदद करता है। File::Find
zwol

6
आपको पता होना चाहिए कि मैं उस दस्तावेज़ से सहमत हूँ, जिसकी आप आलोचना कर रहे हैं और पैट्रिक और टेर्डन के उत्तरों के साथ। मेरा उत्तर पार्सिंग आउटपुट से बचने के लिए एक अतिरिक्त , स्वतंत्र कारण प्रदान करने का था ls
zwol

19
यह बहुत भ्रामक है। शेल एक अच्छी प्रोग्रामिंग भाषा नहीं है, लेकिन केवल इसलिए कि यह एक प्रोग्रामिंग भाषा नहीं है। यह एक स्क्रिप्टिंग भाषा है। और यह एक अच्छी स्क्रिप्टिंग भाषा है।
माइल्स रुट

178

वह लिंक बहुत संदर्भित है क्योंकि जानकारी पूरी तरह से सही है, और यह बहुत लंबे समय से वहां है।


lsगैर-मुद्रण योग्य वर्णों को ग्लोब वर्णों के साथ हाँ में बदल देता है, लेकिन वे वर्ण वास्तविक फ़ाइल नाम में नहीं हैं। यह बात क्यों है? 2 कारण:

  1. यदि आप उस फ़ाइलनाम को किसी प्रोग्राम में पास करते हैं, तो वह फ़ाइलनाम वास्तव में मौजूद नहीं है। यह वास्तविक फ़ाइल नाम प्राप्त करने के लिए ग्लोब का विस्तार करना होगा।
  2. फ़ाइल ग्लोब एक से अधिक फ़ाइल से मेल खा सकता है।

उदाहरण के लिए:

$ touch a$'\t'b
$ touch a$'\n'b
$ ls -1
a?b
a?b

ध्यान दें कि कैसे हमारे पास 2 फाइलें हैं जो बिल्कुल समान दिखती हैं। यदि आप दोनों के रूप में प्रतिनिधित्व करते हैं, तो आप उन्हें कैसे भेद करेंगे a?b?


जब लेखक शेल ग्लब्स वाले फ़ाइलनामों की सूची देता है, तो फ़ाइल नामकरण को इसे फ़ाइल नाम देना कहते हैं और फिर फ़ाइल सूची प्राप्त करने के लिए शेल ग्लोब का उपयोग करने की सलाह देते हैं!

यहाँ एक अंतर है। जब आपको एक ग्लोब वापस मिलता है, जैसा कि दिखाया गया है, कि ग्लोब एक से अधिक फ़ाइल से मेल खा सकता है। हालांकि जब आप एक ग्लोब से मेल खाते परिणामों के माध्यम से पुनरावृत्ति करते हैं, तो आपको सटीक फ़ाइल मिलती है, न कि ग्लोब।

उदाहरण के लिए:

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

ध्यान दें कि xxdआउटपुट कैसे दिखाता है $fileजिसमें कच्चे अक्षर होते हैं \tऔर \n, नहीं ?

यदि आप उपयोग करते हैं ls, तो आपको इसके बदले मिलता है:

for file in $(ls -1q); do printf '%s' "$file" | xxd; done
0000000: 613f 62                                  a?b
0000000: 613f 62                                  a?b

"मैं वैसे भी पुनरावृति करने जा रहा हूं, क्यों नहीं उपयोग करता हूं ls?"

आपके द्वारा दिया गया आपका उदाहरण वास्तव में काम नहीं करता है। ऐसा लगता है कि यह काम करता है, लेकिन यह नहीं है।

मैं इसका उल्लेख कर रहा हूं:

 for f in $(ls -1q | tr " " "?") ; do [ -f "$f" ] && echo "./$f" ; done

मैंने फ़ाइल नामों के एक समूह के साथ एक निर्देशिका बनाई है:

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6120 62                                  a b
0000000: 6120 2062                                a  b
0000000: 61e2 8082 62                             a...b
0000000: 61e2 8083 62                             a...b
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

जब मैं आपका कोड चलाता हूं, तो मुझे यह मिलता है:

$ for f in $(ls -1q | tr " " "?") ; do [ -f "$f" ] && echo "./$f" ; done
./ab
./ab

बाकी फाइलें कहां जाएंगी?

आइए इसके बजाय इसकी कोशिश करें:

$ for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f"; done
stat: cannot stat ‘./a?b’: No such file or directory
stat: cannot stat ‘./a??b’: No such file or directory
./ab
./ab
stat: cannot stat ‘./a?b’: No such file or directory
stat: cannot stat ‘./a?b’: No such file or directory

अब एक वास्तविक ग्लोब का उपयोग करने देता है:

$ for f in *; do stat --format='%n' "./$f"; done
./a b
./a  b
./ab
./ab
./a b
./a
b

बैश के साथ

उपरोक्त उदाहरण मेरे सामान्य खोल, zsh के साथ था। जब मैं बैश के साथ प्रक्रिया दोहराता हूं, तो मुझे आपके उदाहरण के साथ परिणामों का एक और पूरी तरह से अलग सेट मिलता है:

फ़ाइलों का एक ही सेट:

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6120 62                                  a b
0000000: 6120 2062                                a  b
0000000: 61e2 8082 62                             a...b
0000000: 61e2 8083 62                             a...b
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

आपके कोड के साथ अलग-अलग परिणाम:

for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f"; done
./a b
./ab
./ab
./a b
./a
b
./a  b
./ab
./ab
./a b
./ab
./ab
./a b
./a
b
./a b
./ab
./ab
./a b
./a
b

एक शेल गोला के साथ, यह पूरी तरह से ठीक काम करता है:

$ for f in *; do stat --format='%n' "./$f"; done
./a b
./a  b
./ab
./ab
./a b
./a
b

बैश इस तरह से व्यवहार करता है, जो मैंने उत्तर की शुरुआत में किए गए बिंदुओं में से एक पर वापस जाता है: "फ़ाइल ग्लोब एक से अधिक फ़ाइल से मेल खा सकता है"।

lsa?bकई फ़ाइलों के लिए एक ही ग्लोब ( ) लौटा रहा है , इसलिए हर बार जब हम इस ग्लोब का विस्तार करते हैं, तो हमें हर एक फाइल मिलती है जो इससे मेल खाती है।


उन फ़ाइलों की सूची को पुनः बनाने के लिए जो मैं उपयोग कर रहा था:

touch 'a b' 'a  b' a$'\xe2\x80\x82'b a$'\xe2\x80\x83'b a$'\t'b a$'\n'b

हेक्स कोड वाले UTF-8 NBSP अक्षर हैं।


5
@mikeserv वास्तव में उसका समाधान एक ग्लोब वापस नहीं करता है। मैंने उस बिंदु को स्पष्ट करने के लिए अपना उत्तर अपडेट किया।
पैट्रिक

18
"बाकी नहीं"? यह असंगत व्यवहार है, और अप्रत्याशित परिणाम, यह कैसे एक कारण है?
पैट्रिक

11
@mikeserv क्या आपने अपने प्रश्न पर मेरी टिप्पणी नहीं देखी? शेल ग्लोबिंग की तुलना में 2.5 गुना तेज है ls। मैंने यह भी अनुरोध किया कि आप अपने कोड का परीक्षण करें क्योंकि यह काम नहीं करता है। इसमें से किसी के साथ zsh का क्या संबंध है?
पैट्रिक

27
@mikeserv नहीं, यह सब अभी भी बैश करने के लिए लागू होता है। हालांकि मैं इस सवाल के साथ कर रहा हूँ क्योंकि आप जो मैं कह रहा हूँ उसे नहीं सुन रहे हैं।
पैट्रिक

7
आप जानते हैं कि, मुझे लगता है कि मैं इस उत्तर को बढ़ा दूंगा और स्पष्ट कर दूंगा कि मैं उसकी हर बात से सहमत हूं। ;-)
zwol

54

चलो कोशिश करते हैं और थोड़ा सरल करते हैं:

$ touch a$'\n'b a$'\t'b 'a b'
$ ls
a b  a?b  a?b
$ IFS="
"
$ set -- $(ls -1q | uniq)
$ echo "Total files in shell array: $#"
Total files in shell array: 4

देख? यह पहले से ही गलत है। 3 फाइलें हैं लेकिन बैश रिपोर्टिंग कर रही है। 4. यह इसलिए है क्योंकि इसमें setउत्पन्न ग्लब्स दिए जा lsरहे हैं, जिन्हें पास किए जाने से पहले शेल द्वारा विस्तारित किया जाता है set। यही कारण है कि आप प्राप्त करते हैं:

$ for x ; do
>     printf 'File #%d: %s\n' $((i=$i+1)) "$x"
> done
File #1: a b
File #2: a b
File #3: a    b
File #4: a
b

या, यदि आप पसंद करते हैं:

$ printf ./%s\\0 "$@" |
> od -A n -c -w1 |
> sed -n '/ \{1,3\}/s///;H
> /\\0/{g;s///;s/\n//gp;s/.*//;h}'
./a b
./a b
./a\tb
./a\nb

ऊपर चलाया गया था bash 4.2.45


2
मैंने इसे उकेरा। आपका अपना कोड आपको देखकर अच्छा लगता है। लेकिन सिर्फ इसलिए कि मुझे गलत लगा इसका मतलब यह नहीं है कि इसे सही नहीं किया जा सकता। मैंने आपको आज सुबह इसे करने के लिए एक बहुत ही सरल तरीका दिखाया ls -1qRi | grep -o '^ *[0-9]*'- जो कि पार्सिंग lsआउटपुट है, यार, और यह सबसे तेज और सबसे अच्छा तरीका है, जिसे मैं इनोड नंबर की एक सूची प्राप्त करना जानता हूं।
14:56

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

@ cHao - मैंने इसकी खूबियों का तर्क नहीं दिया - मैंने इसके प्रचार का विरोध किया।
mikeserv

16
@mikeserv: इसके खिलाफ तर्क अच्छी तरह से स्थापित और अच्छी तरह से योग्य हैं। यहां तक ​​कि आपने उन्हें सच कर दिखाया है।
cHao

1
@cHao - मैं असहमत हूं। मंत्र और ज्ञान के बीच एक नहीं तो ठीक-ठीक रेखा है।
mikeserv

50

आउटपुट में ls -qग्लोब बिल्कुल नहीं है। इसका ?अर्थ है "यहाँ एक चरित्र है जिसे सीधे प्रदर्शित नहीं किया जा सकता है"। ग्लोब्स का ?अर्थ है "किसी भी चरित्र को यहां अनुमति दी जाती है"।

ग्लब्स में अन्य विशेष वर्ण हैं ( *और []कम से कम, और []जोड़ी के अंदर अधिक हैं)। इनमें से कोई भी व्यक्ति बच नहीं पाता है ls -q

$ touch x '[x]'
$ ls -1q
[x]
x

यदि आप ls -1qआउटपुट का इलाज करते हैं तो ग्लब्स का एक सेट होता है और उनका विस्तार होता है, न केवल आपको xदो बार मिलेगा , आप [x]पूरी तरह से याद करेंगे । एक ग्लोब के रूप में, यह एक स्ट्रिंग के रूप में खुद से मेल नहीं खाता है।

ls -q अपनी आंखों और / या टर्मिनल को पागल पात्रों से बचाने के लिए है, न कि कुछ ऐसा बनाने के लिए जिसे आप शेल में वापस फीड कर सकते हैं।


42

उत्तर सरल है: आप के विशेष मामलों को lsकिसी भी संभावित लाभ से आगे बढ़ना है। यदि आप lsआउटपुट को पार्स नहीं करते हैं तो इन विशेष मामलों से बचा जा सकता है ।

यहाँ मंत्र कभी भी उपयोगकर्ता फाइल सिस्टम ( उपयोगकर्ता इनपुट पर भरोसा नहीं करने के बराबर ) पर भरोसा नहीं करता है । यदि कोई ऐसा तरीका है जो हमेशा काम करेगा, तो 100% निश्चितता के साथ, यह वह विधि होनी चाहिए जिसे आप पसंद करते हैं भले lsही वही करें लेकिन कम निश्चितता के साथ। मैं तकनीकी विवरणों में नहीं जाऊंगा क्योंकि वे टेर्डन और पैट्रिक द्वारा बड़े पैमाने पर कवर किए गए थे । मुझे पता है कि lsएक महत्वपूर्ण (और शायद महंगा) लेनदेन में उपयोग करने के जोखिम के कारण जहां मेरी नौकरी / प्रतिष्ठा लाइन पर है, मैं किसी भी समाधान को पसंद करूंगा जिसमें अनिश्चितता का ग्रेड नहीं है अगर इसे टाला जा सकता है।

मुझे पता है कि कुछ लोग निश्चितता पर कुछ जोखिम पसंद करते हैं , लेकिन मैंने एक बग रिपोर्ट दर्ज की है


33

लोगों का कहना है कि ऐसा कुछ भी कभी नहीं करना चाहिए क्योंकि यह बिल्कुल सकारात्मक रूप से सही तरीके से नहीं किया जा सकता है। हम ऐसा करने में सक्षम हो सकते हैं, लेकिन यह अधिक जटिल, कम कुशल दोनों जगह- या समय-वार हो सकता है। उदाहरण के लिए यह कहना बिल्कुल ठीक होगा कि "x86 असेंबली में एक बड़े ई-कॉमर्स बैकेंड का निर्माण न करें"।

तो अब इस मुद्दे को हाथ में लें: जैसा कि आपने प्रदर्शित किया है कि आप एक ऐसा समाधान बना सकते हैं जो पार्स करता है और सही परिणाम देता है - इसलिए शुद्धता कोई समस्या नहीं है।

क्या यह अधिक जटिल है? हाँ, लेकिन हम एक सहायक समारोह के पीछे छिपा सकते हैं।

तो अब दक्षता के लिए:

अंतरिक्ष-दक्षता: आपका समाधान uniqडुप्लिकेट को फ़िल्टर करने पर निर्भर करता है , फलस्वरूप हम आलसी परिणाम उत्पन्न नहीं कर सकते हैं। तो या तो O(1)बनाम O(n)या दोनों है O(n)

समय-दक्षता: सबसे अच्छा मामला uniqहैशमैप दृष्टिकोण का उपयोग करता है इसलिए हमारे पास अभी भी खरीदे गएO(n) तत्वों की संख्या में एक एल्गोरिथ्म है , हालांकि यह है ।O(n log n)

अब असली समस्या: जबकि आपका एल्गोरिथ्म अभी भी बहुत बुरा नहीं लग रहा है मैं खरीदे गए तत्वों और एन के लिए तत्वों का उपयोग करने के लिए वास्तव में सावधान था । क्योंकि इससे बहुत फर्क पड़ता है। मान लें कि आपके पास एक फ़ाइल \n\nहै, जिसके परिणामस्वरूप ??लिस्टिंग में प्रत्येक 2 वर्ण फ़ाइल से मेल खाता है। मजेदार रूप से यदि आपके पास एक और फ़ाइल \n\rहै, जिसके परिणामस्वरूप ??भी और सभी 2 वर्ण फ़ाइलों को भी वापस कर देगा .. तो देखें कि यह कहाँ जा रहा है? रैखिक व्यवहार के बजाय घातांक निश्चित रूप से "बदतर रनटाइम व्यवहार" के रूप में योग्य है .. यह एक व्यावहारिक एल्गोरिथ्म और आप के बारे में सैद्धांतिक सीएस पत्रिकाओं में पत्र लिखने के बीच का अंतर है।

हर कोई उदाहरण सही प्यार करता है? ये रहा। "परीक्षण" नामक एक फ़ोल्डर बनाएं और इस पायथन स्क्रिप्ट का उपयोग उसी निर्देशिका में करें जहां फ़ोल्डर है।

#!/usr/bin/env python3
import itertools
dir = "test/"
filename_length = 3
options = "\a\b\t\n\v\f\r"

for filename in itertools.product(options, repeat=filename_length):
        open(dir + ''.join(filename), "a").close()

केवल एक चीज यह 7 पात्रों के लिए लंबाई 3 के सभी उत्पादों को उत्पन्न करती है। हाई स्कूल गणित हमें बताता है कि 343 फाइलें होनी चाहिए। ठीक है कि वास्तव में मुद्रित करने के लिए जल्दी होना चाहिए, तो चलो देखते हैं:

time for f in *; do stat --format='%n' "./$f" >/dev/null; done
real    0m0.508s
user    0m0.051s
sys 0m0.480s

चलिए अब आपका पहला उपाय आजमाते हैं, क्योंकि मैं वास्तव में इसे प्राप्त नहीं कर सकता

eval set -- $(ls -1qrR ././ | tr ' ' '?' |
sed -e '\|^\(\.\{,1\}\)/\.\(/.*\):|{' -e \
        's//\1\2/;\|/$|!s|.*|&/|;h;s/.*//;b}' -e \
        '/..*/!d;G;s/\(.*\)\n\(.*\)/\2\1/' -e \
        "s/'/'\\\''/g;s/.*/'&'/;s/?/'[\"?\$IFS\"]'/g" |
uniq)

यहाँ लिनक्स टकसाल 16 पर काम करने के लिए (जो मुझे लगता है कि इस पद्धति की प्रयोज्यता के लिए वॉल्यूम बोलता है)।

किसी भी तरह से ऊपर बहुत अधिक केवल परिणाम प्राप्त करने के बाद इसे फ़िल्टर करता है, पहले वाला समाधान कम से कम उतना ही जल्दी होना चाहिए जितना कि (उस एक में कोई इनकोड ट्रिक नहीं है - लेकिन वे अविश्वसनीय हैं ताकि आप शुद्धता को छोड़ दें)।

तो अब कब तक करता

time for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f" >/dev/null; done

लेना? वैसे मैं वास्तव में नहीं जानता, 343 ^ 343 फ़ाइल नामों की जांच करने में थोड़ा समय लगता है - मैं आपको ब्रह्मांड की गर्मी से मृत्यु के बाद बताऊंगा।


6
बेशक, जैसा कि एक अन्य जवाब के तहत टिप्पणियों में उल्लेख किया गया है , "... आपने जो प्रदर्शन किया है वह एक समाधान बना सकता है जो एलएस को पार्स करता है और सही परिणाम देता है ..." वास्तव में सच नहीं है।
वाइल्डकार्ड

26

ओपी के मंचन को संबोधित किया

प्रस्तावना और मूल जवाब के औचित्य 2015/05/18 पर अद्यतन

mikeserv (ओपी) ने अपने प्रश्न के नवीनतम अपडेट में कहा: "मैं इसे एक शर्म की बात मानता हूं, हालांकि मैंने पहली बार यह सवाल गलत सूचना के स्रोत को इंगित करने के लिए कहा था, और, दुर्भाग्य से, यहां सबसे उत्कीर्ण जवाब बड़े हिस्से में भ्रामक है। "

चलो ठीक है; मुझे लगता है कि यह बहुत शर्म की बात है कि मैंने यह जानने में बहुत समय बिताया कि मैं अपने अर्थ को कैसे समझाऊं कि मैं प्रश्न को फिर से पढ़ूं। यह सवाल "बल्कि उत्तर से [पैदा] चर्चा" समाप्त हो गया और पर में वजन समाप्त हो गया पाठ का ~ 18K (अकेले ही इस सवाल के लिए, बस स्पष्ट होना) जो लंबे समय से यहां तक कि एक ब्लॉग पोस्ट के लिए किया जाएगा।

लेकिन StackExchange आपका साबुनबॉक्स नहीं है, और यह आपका ब्लॉग नहीं है। हालांकि, वास्तव में, आपने इसे कम से कम दोनों के रूप में उपयोग किया है। लोगों ने लोगों के वास्तविक सवालों के जवाब देने के बजाय आपके "टू-पॉइंट-आउट" का जवाब देने में बहुत समय लगाया। इस बिंदु पर, मैं प्रश्न को हमारे प्रारूप के लिए अच्छा नहीं होने के रूप में चिह्नित करूंगा, यह देखते हुए कि ओपी ने स्पष्ट रूप से कहा है कि यह बिल्कुल भी प्रश्न होने का इरादा नहीं था।

इस बिंदु पर मुझे यकीन नहीं है कि मेरा जवाब इस बिंदु पर था या नहीं; शायद नहीं, लेकिन यह आपके कुछ सवालों पर निर्देशित था, और शायद यह किसी और के लिए उपयोगी उत्तर हो सकता है; शुरुआती दिल लेते हैं, उनमें से कुछ "एक बार कभी-कभी" कर लेते हैं और जब आप अधिक अनुभवी हो जाते हैं। :)

एक सामान्य नियम के रूप में...

कृपया शेष मोटे किनारों को माफ कर दें; मैं इस पर पहले से ही बहुत अधिक समय बिता रहा हूं ... ओपी को सीधे उद्धृत करने के बजाय (जैसा कि मूल रूप से इरादा है) मैं संक्षेप में प्रस्तुत करने का प्रयास करूंगा।

[मुख्य रूप से मेरे मूल उत्तर से पुनःप्राप्त]
विचार करने पर, मेरा मानना ​​है कि ओपी ने मेरे द्वारा पूछे गए प्रश्नों पर जोर दिया है; हालाँकि, संबोधित किए गए बिंदुओं को लाया गया था, और मैंने उन उत्तरों को काफी हद तक बरकरार रखा है, क्योंकि मेरा मानना ​​है कि उन्हें टू-पॉइंट होना चाहिए और उन मुद्दों को संबोधित करना है जिन्हें मैंने अन्य संदर्भों में लाया है और साथ ही साथ शुरुआती लोगों को सलाह भी दी है।

मूल पोस्ट ने पूछा, कई मायनों में, विभिन्न लेखों ने सलाह क्यों दी जैसे कि «डोंट पार्से lsआउटपुट» या «आपको कभी भी lsआउटपुट पार्स नहीं करना चाहिए , और इसके आगे।

इस मुद्दे के बारे में मेरा सुझाव दिया गया है कि इस तरह के बयान के उदाहरण केवल एक मुहावरे के उदाहरण हैं, जिन्हें थोड़ा अलग तरीके से चित्रित किया गया है, जिसमें एक पूर्ण मात्रात्मक को एक अनिवार्यता के साथ जोड़ा जाता है [जैसे, «नहीं [कभी] एक्स», «[आपको] हमेशा वाई», «[एक चाहिए] कभी नहीं जेड»] सामान्य नियमों या दिशानिर्देशों के रूप में इस्तेमाल किए जाने वाले बयान बनाने के लिए, खासकर जब किसी विषय पर उन नए लोगों को दिया जाता है, बजाय निरपेक्ष सत्य के रूप में इरादा किए, उन बयानों के बावजूद स्पष्ट रूप

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

और ऐसा तब है, जब एक विशेषज्ञ, शायद, "द रूल्स" के उल्लंघन में चीजों का चयन कर सकता है। लेकिन इससे उन्हें कोई "नियम" कम नहीं लगेंगे।

और, इसलिए, हाथ में विषय के लिए: मेरे विचार में, सिर्फ इसलिए कि एक विशेषज्ञ पूरी तरह से स्मैक किए बिना इस नियम का उल्लंघन करने में सक्षम हो सकता है, मुझे ऐसा कोई तरीका नहीं दिखाई देता है जिसे आप एक शुरुआत बताने वाले को सही ठहरा सकें कि "कभी-कभी" lsआउटपुट को पार्स करने के लिए ठीक है , क्योंकि: यह नहीं है । या, कम से कम, निश्चित रूप से एक शुरुआत के लिए ऐसा करना सही नहीं है।

आप हमेशा अपने प्यादों को केंद्र में रखते हैं; उद्घाटन में एक टुकड़ा, एक चाल; जल्द से जल्द अवसर पर महल; बिशप से पहले शूरवीर; रिम पर एक शूरवीर गंभीर है; और हमेशा सुनिश्चित करें कि आप अपनी गणना अंत तक देख सकते हैं! (वूप्स, सॉरी, थक गया, यह शतरंज के StackExchange के लिए है।)

नियम, टूटे होने का मतलब है?

किसी विषय पर एक लेख पढ़ते समय, जिस पर लक्षित किया जाता है, या शुरुआती द्वारा पढ़ने की संभावना है, अक्सर आप इस तरह की चीजें देखेंगे:

  • "आपको कभी एक्स नहीं करना चाहिए। "
  • "कभी क्यू नहीं करते!"
  • "जेड मत करो।"
  • "एक को हमेशा वाई करना चाहिए!"
  • "सी, कोई बात नहीं।"

जबकि ये कथन निश्चित रूप से निरपेक्ष और कालातीत नियमों को बताते हुए प्रतीत होते हैं, वे नहीं हैं; इसके बजाय यह सामान्य नियमों [aka "दिशा-निर्देशों", "अंगूठे के नियम", "मूल बातें", इत्यादि को बताने का एक तरीका है] जो कि उन लेखों को पढ़ने वाले शुरुआती लोगों के लिए उन्हें बताने के लिए कम से कम यकीनन एक उपयुक्त तरीका है। हालांकि, सिर्फ इसलिए कि उन्हें निरपेक्ष के रूप में कहा गया है, नियम निश्चित रूप से पेशेवरों और विशेषज्ञों को नहीं बांधते हैं [जो लोग संभवतः ऐसे नियमों को पहले स्थान पर संक्षेप में प्रस्तुत करते थे, रिकॉर्ड करने और ज्ञान प्राप्त करने के तरीके के रूप में वे आवर्ती के साथ निपटाते थे। उनके विशेष शिल्प में समस्याएं।]

वे नियम निश्चित रूप से प्रकट नहीं करने जा रहे हैं कि एक विशेषज्ञ एक जटिल या बारीक समस्या से कैसे निपटेगा, जिसमें, कहते हैं, वे नियम एक-दूसरे के साथ संघर्ष करते हैं; या जिन चिंताओं के कारण नियम पहली जगह पर लागू होता है, वे लागू नहीं होते हैं। विशेषज्ञों को डर नहीं है (या डर नहीं होना चाहिए!) बस नियमों को तोड़ दें जो उन्हें पता है कि किसी विशेष स्थिति में समझ में नहीं आता है। विशेषज्ञ अपने शिल्प में विभिन्न जोखिमों और चिंताओं को संतुलित करने के लिए लगातार काम कर रहे हैं, और अक्सर अपने फैसले का उपयोग उन प्रकार के नियमों को तोड़ने के लिए करना चाहिए, विभिन्न कारकों को संतुलित करने और नियमों का पालन करने के लिए नियमों की तालिका पर निर्भर नहीं होने के कारण। Gotoएक उदाहरण के रूप में लें : एक लंबा, आवर्ती, बहस है कि क्या वे हानिकारक हैं। (हाँ, कभी गोटो का उपयोग न करें; डी)

एक मॉडल का प्रस्ताव

एक विषम विशेषता, कम से कम अंग्रेजी में, और मैं कई अन्य भाषाओं में, सामान्य नियमों की कल्पना करता हूं, यह है कि उन्हें एक ही रूप में एक प्रस्ताव के रूप में कहा गया है, फिर भी एक क्षेत्र के विशेषज्ञ एक सामान्य नियम देने के लिए तैयार हैं स्थिति, सभी जानते हुए भी कि वे उचित होने पर नियम को तोड़ देंगे। स्पष्ट रूप से, इसलिए, ये कथन मोडल लॉजिक के समान बयानों के समतुल्य नहीं हैं।

यही कारण है कि मैं कहता हूं कि वे केवल मुहावरेदार होना चाहिए। वास्तव में "कभी नहीं" या "हमेशा" स्थिति होने के बजाय, ये नियम आमतौर पर सामान्य दिशानिर्देशों को संहिताबद्ध करने के लिए काम करते हैं, जो विस्तृत परिस्थितियों में उचित होते हैं, और यह कि जब शुरुआती लोग आँख बंद करके इनका पालन करते हैं, तो इसका परिणाम बहुत दूर तक हो सकता है। अच्छे परिणाम के बिना उनके खिलाफ जाने की शुरुआत करने वाले की तुलना में बेहतर परिणाम। कभी-कभी वे नियमों को संहिताबद्ध करते हैं, नियमों के विपरीत जाने पर गलत विकल्पों के साथ एकमुश्त असफलताओं के बजाय केवल घटिया परिणामों की ओर अग्रसर होते हैं।

इसलिए, सामान्य नियम पूर्ण मोडल प्रस्ताव नहीं हैं जो वे सतह पर दिखाई देते हैं, लेकिन इसके बजाय नियम को एक मानक बायलरप्लेट निहित के साथ देने का एक संक्षिप्त तरीका है, निम्न में से कुछ:

जब तक आपके पास यह बताने की क्षमता नहीं है कि यह दिशानिर्देश किसी विशेष मामले में गलत है, और अपने आप को साबित करें कि आप सही हैं, तो $ {UULE}

जहां, निश्चित रूप से आप ls$ {RULE} के स्थान पर "कभी भी पार्स आउटपुट" को स्थानापन्न नहीं कर सकते । :)

अरे हां! पार्सिंग आउटपुट के बारे में क्या ls?

ठीक है, इसलिए, यह सब देखते हुए ... मुझे लगता है कि यह स्पष्ट है कि यह नियम एक अच्छा है। सबसे पहले, वास्तविक नियम को मुहावरेदार समझना होगा, जैसा कि ऊपर बताया गया है ...

लेकिन इसके अलावा, यह सिर्फ यह नहीं है कि आपको यह जानने के लिए शेल स्क्रिप्टिंग के साथ बहुत अच्छा होना चाहिए कि क्या यह टूट सकता है, किसी विशेष मामले में। यह भी है, कि जब आपको परीक्षण में इसे तोड़ने की कोशिश की जा रही है, तो आपको इसे गलत बताने के लिए बस उतना ही कौशल चाहिए ! और, मैं विश्वास के साथ कहता हूं कि इस तरह के लेखों के संभावित दर्शकों का एक बहुत बड़ा हिस्सा («आउटपुट को पार्स न करें ls!) जैसी सलाह उन चीजों को नहीं कर सकता है , और जिनके पास ऐसा कौशल है, उन्हें इसका एहसास होगा! वे इसे अपने दम पर समझ लेते हैं और वैसे भी नियम की अनदेखी करते हैं।

लेकिन ... बस इस सवाल को देखें, और यह भी कि कैसे लोगों को शायद कौशल है कि ऐसा करने के लिए एक बुरा फोन था सोचा था; और प्रश्न के लेखक ने वर्तमान सर्वश्रेष्ठ उदाहरण के एक बिंदु तक पहुंचने में कितना प्रयास किया! मैं आपको एक समस्या पर गारंटी देता हूं कि कठिन, 99% लोग इसे गलत समझेंगे, और संभावित रूप से बहुत खराब परिणाम के साथ! भले ही जिस विधि पर निर्णय लिया जाता है वह एक अच्छा हो जाता है; जब तक यह (या कोई अन्य) lsपार्सिंग विचार पूरी तरह से आईटी / डेवलपर लोक द्वारा अपनाया नहीं जाता है, तब तक बहुत सारे परीक्षण (विशेष रूप से समय की परीक्षा) और अंत में, एक 'सामान्य तकनीक' की स्थिति में स्नातक होने का प्रबंधन करता है, यह संभावना है कि ए बहुत से लोग इसे आज़मा सकते हैं, और इसे गलत कर सकते हैं ... विनाशकारी परिणामों के साथ।

तो, मैं एक आखिरी बार दोहराना होगा .... कि, विशेष रूप से इस मामले में , कि यही वजह है कि " कभी नहीं पार्स lsउत्पादन!" निश्चित रूप से यह वाक्यांश का सही तरीका है।

[अद्यतन 2014-05-18: ओपी की टिप्पणी का जवाब देने के लिए उत्तर (ऊपर) के लिए स्पष्ट तर्क; निम्नलिखित जोड़ ओपी के कल के सवाल के जवाब में है]

[अद्यतन २०१४-११-१०: जोड़े गए हेडर और पुनर्गठित / रिफलेक्टेड सामग्री; और यह भी: सुधार, rewording, स्पष्ट, और उम ... "संक्षिप्त-ifying" ... मैं यह सिर्फ एक साफ-सुथरा होने का इरादा था, हालांकि यह एक rework के एक बिट में बदल गया। मैंने इसे खेदजनक स्थिति में छोड़ दिया था, इसलिए मैंने मुख्य रूप से इसे कुछ आदेश देने की कोशिश की। मैंने महसूस किया कि बड़े पैमाने पर पहले खंड को बरकरार रखना महत्वपूर्ण था; इसलिए केवल दो छोटे बदलाव वहाँ निरर्थक 'लेकिन' हटाए गए, और 'उस' पर ज़ोर दिया गया।]

† मैंने मूल रूप से इसे केवल अपने मूल पर स्पष्टीकरण के रूप में रखा था; लेकिन प्रतिबिंब पर अन्य परिवर्धन पर फैसला किया

‡ पदों पर दिशानिर्देशों के लिए https://unix.stackexchange.com/tour देखें


2
मुहावरेदार कभी नहीं है। यह किसी भी चीज का जवाब नहीं है।
अभ्रक

1
हम्म। खैर, मुझे नहीं पता था कि यह जवाब संतोषजनक होगा या नहीं, लेकिन मुझे उम्मीद है कि यह विवादास्पद नहीं होगा । और, मैंने नहीं किया (मतलब है) का तर्क है कि 'कभी नहीं' प्रति मुहावरेदार था; लेकिन वह "कभी एक्स नहीं करता है!" एक मुहावरेदार उपयोग है । मुझे दो सामान्य मामले दिखाई देते हैं जो दिखा सकते हैं कि 'नेवर / पार्स नहीं ls!' सही सलाह है: 1. प्रदर्शन (अपनी संतुष्टि के लिए) कि हर उपयोग-मामले में जहां कोई lsआउटपुट पार्स कर सकता है उसके पास एक और उपलब्ध समाधान है, किसी भी तरह से बेहतर, ऐसा किए बिना। 2. यह दिखाएं कि उद्धृत मामलों में, कथन शाब्दिक नहीं है।
शेलीबटरफ्लाई

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

1
मुझे उस पोस्ट को साफ करना चाहिए। फिर भी, कभी नहीं है नहीं यह वाक्यांश के लिए सही रास्ता। यह थोड़ा हास्यास्पद है कि लोग सोचते हैं कि वे दूसरों को कभी नहीं बताने के लिए योग्य हैं या नहीं - बस उन्हें बताएं कि आपको नहीं लगता कि यह काम करेगा और क्यों, लेकिन आप जानते हैं कि क्या काम करेगा और क्यों। lsएक कंप्यूटर उपयोगिता है - आप कंप्यूटर आउटपुट
मिकसेर्व

1
ठीक है, मैंने अपने डाउनवोट को उलट दिया क्योंकि, बहुत कम से कम, झंडे वाली बात के बारे में आप सही हैं। बीमार आज रात या कल इसे साफ करने की कोशिश करेंगे। मेरा विचार है कि मैं एक जवाब मुझे लगता है कि कोड उदाहरण के सबसे कदम होगा। लेकिन यह अभी भी सम्‍मिलित नहीं है, जहाँ तक im का संबंध है, उस अछूते ब्‍लॉग पोस्‍ट में अशुद्धियों का बहाना है। काश लोग पूरी तरह से बैश मैनुअल का हवाला देना बंद कर देते - कम से कम तिल के बाद वे
पोस

16

क्या lsकुछ मामलों में आउटपुट को पार्स करना संभव है ? ज़रूर। एक निर्देशिका से इनोड संख्याओं की सूची निकालने का विचार एक अच्छा उदाहरण है - यदि आप जानते हैं कि आपके कार्यान्वयन का lsसमर्थन करता है -q, और इसलिए प्रत्येक फ़ाइल आउटपुट की बिल्कुल एक पंक्ति का उत्पादन करेगी, और आप सभी को इनोड संख्याओं की आवश्यकता होती है, उन्हें रोककर पार्स करना ls -Rai1qउत्पादन निश्चित रूप से एक संभव समाधान है। बेशक, अगर लेखक ने पहले कभी "एलएस के आउटपुट को पार्स न करें" जैसी सलाह नहीं देखी थी, तो वह शायद उन पर नई कहानियों के साथ फाइलनाम के बारे में नहीं सोचेगा, और शायद परिणामस्वरूप 'क्यू' छोड़ देगा, और कोड उस किनारे के मामले में सूक्ष्म रूप से टूट जाएगा - इसलिए, उन मामलों में भी जहां पार्सिंग lsका आउटपुट उचित है, यह सलाह अभी भी उपयोगी है।

व्यापक बिंदु यह है कि, जब कोई नौसिखिया शेल स्क्रिप्टिंग करने के लिए एक स्क्रिप्ट का पता लगाने की कोशिश करता है (उदाहरण के लिए) एक निर्देशिका में सबसे बड़ी फ़ाइल क्या है, या एक निर्देशिका में सबसे हाल ही में संशोधित फ़ाइल क्या है, तो उसकी पहली वृत्ति को पार्स करना है ls। आउटपुट - समझ में आता है, क्योंकि lsपहला कमांड एक नौसिखिया सीखता है।

दुर्भाग्य से, वह वृत्ति गलत है, और वह दृष्टिकोण टूट गया है। इससे भी अधिक दुर्भाग्य से, यह सूक्ष्म रूप से टूट गया है - यह ज्यादातर समय काम करेगा, लेकिन किनारे के मामलों में विफल हो सकता है जो कोड के ज्ञान के साथ किसी के द्वारा शोषण किया जा सकता है।

नौसिखिया ls -s | sort -n | tail -n 1 | awk '{print $2}'एक निर्देशिका में सबसे बड़ी फ़ाइल प्राप्त करने के तरीके के रूप में सोच सकता है । और यह तब तक काम करता है, जब तक आपके पास नाम की जगह के साथ फाइल नहीं है।

ठीक है, तो कैसे ls -s | sort -n | tail -n 1 | sed 's/[^ ]* *[0-9]* *//'? तब तक ठीक काम करता है जब तक आपके पास नाम में एक नईलाइन के साथ एक फ़ाइल नहीं है।

जोड़ने करता है -qकरने के लिए lsकी बहस जब वहाँ फ़ाइल नाम में एक नई पंक्ति की मदद? ऐसा लग सकता है, जब तक आपके पास 2 अलग-अलग फाइलें हैं, जिसमें फ़ाइल नाम में एक ही स्थान पर एक गैर-मुद्रण योग्य चरित्र होता है, और तब lsआउटपुट आपको उन सबसे अलग नहीं होने देता है जो सबसे बड़ा था। इससे भी बदतर, "का विस्तार करने के लिए?", वह शायद अपने खोल का समर्थन करता है eval- जो समस्याओं का कारण होगा यदि वह उदाहरण के लिए नाम की फ़ाइल को हिट करता है,

foo`/tmp/malicious_script`bar

--quoting-style=shellमदद करता है (यदि आपका lsभी इसे समर्थन करता है)? नहीं, अभी भी प्रदर्शित करता है? गैर-वर्णों के वर्णों के लिए, इसलिए यह अभी भी अस्पष्ट है कि कई मैचों में से कौन सा सबसे बड़ा था। --quoting-style=literal? नहीं, वही। --quoting-style=localeया --quoting-style=cअगर आपको बस सबसे बड़ी फ़ाइल के नाम को स्पष्ट रूप से प्रिंट करने की आवश्यकता है, लेकिन संभवत: यदि आपको फ़ाइल के साथ कुछ करने की आवश्यकता नहीं है, तो - यह कोड का एक गुच्छा होगा जो कि उद्धरण को पूर्ववत करने और वास्तविक फ़ाइल नाम पर वापस लाने के लिए होगा। कि आप इसे gzip कह सकते हैं।

और उस सभी काम के अंत में, भले ही उसके पास जो कुछ भी हो, वह सभी संभावित फ़ाइल नाम के लिए सुरक्षित और सही हो, यह अपठनीय और अचूक है, और इसे बहुत आसानी से, सुरक्षित रूप से, और आसानी से अजगर या एलएल या रूबी में किया जा सकता है।

या यहां तक ​​कि अन्य शेल टूल्स का उपयोग करते हुए - मेरे सिर के ऊपर से, मुझे लगता है कि इस चाल को करना चाहिए:

find . -type f -printf "%s %f\0" | sort -nz | awk 'BEGIN{RS="\0"} END{sub(/[0-9]* /, "", $0); print}'

और कम से कम पोर्टेबल होना चाहिए --quoting-style


ओह आकार के बारे में सच है - मैं शायद यह कर सकता था कि अगर मैंने कोशिश की - तो मुझे करना चाहिए? Im थोड़े थक गए या यह पूरी बात - मुझे आपका जवाब पसंद है क्योंकि आप नहीं कह सकते हैं या नहीं या कभी नहीं, लेकिन वास्तव में शायद उदाहरण देते हैं कि क्यों नहीं और तुलनीय और कैसे - धन्यवाद।
15

मुझे लगता है कि अगर आपने कोशिश की, तो आपको लगता है कि यह आपके हिसाब से बहुत कठिन है। तो, हाँ, मैं कोशिश करूँगा। मुझे उन फिल्नामों को देते रहने में खुशी होगी जो आपके लिए तब तक टूटेंगे जब तक मैं उनके बारे में सोच सकता हूं। :)
गॉडलीजेक

टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
terdon

@mikeserv और Godlygeek, मैंने इस टिप्पणी धागे को चैट में स्थानांतरित कर दिया है । कृपया टिप्पणियों में इस तरह की लंबी चर्चा न करें, यही चैट के लिए है।
terdon
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.