मैं लगातार इस लिंक को निश्चित रूप से बताते हुए उत्तर देता हूं "डोंट पार्से ls
!" यह मुझे कुछ कारणों से परेशान करता है:
ऐसा लगता है कि इस लिंक में जानकारी को छोटे प्रश्न के साथ थोक स्वीकार किया गया है, हालांकि मैं आकस्मिक पढ़ने में कम से कम कुछ त्रुटियां उठा सकता हूं।
यह भी लगता है जैसे कि लिंक में बताई गई समस्याओं ने समाधान खोजने की कोई इच्छा नहीं जगाई है।
पहले पैराग्राफ से:
... जब आप
[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
तो bash
। zsh
- डिफ़ॉल्ट रूप से - शब्द-विभाजन $(
आदेश को )
पोर्टेबल तरीके से प्रतिस्थापित नहीं करता है। इसलिए जब वह पूछता है कि बाकी फाइलें कहां गईं ? इस सवाल का जवाब है कि आपका खोल उन्हें खा गया। यही कारण है कि आपको पोर्टेबल शेल कोड 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
विकल्प और इसके लिए ls
POSIX निर्दिष्ट -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 निर्दिष्ट विकल्प है।
stat
अपने उत्तर में उपयोग कर रहा था , क्योंकि यह वास्तव में जांचता है कि प्रत्येक फ़ाइल मौजूद है। sed
चीज़ के साथ नीचे की ओर आपका बिट काम नहीं करता है।
ls
कि पहले स्थान पर पार्स न करें ? आप जो वर्णन कर रहे हैं वह बहुत कठिन है। मुझे यह सब समझने के लिए इसका पुनर्निर्माण करना होगा और मैं अपेक्षाकृत सक्षम उपयोगकर्ता हूं। आप संभवतः अपने औसत जो से इस तरह के कुछ से निपटने में सक्षम होने की उम्मीद नहीं कर सकते।
ls
आउटपुट गलत होने के सभी कारणों को मूल लिंक में अच्छी तरह से कवर किया गया था (और अन्य जगहों पर भी)। अगर ओपी इसे समझने में मदद मांग रहा होता, तो यह सवाल वाजिब होता, लेकिन इसके बजाय ओपी सिर्फ यह साबित करने की कोशिश कर रहा है कि उसका गलत इस्तेमाल ठीक है।
parsing ls is bad
। for something in $(command)
सटीक परिणाम प्राप्त करने के लिए शब्द-बंटवारे पर करना और भरोसा करना बड़े बहुमत के लिए बुरा है, command's
जिसमें सरल आउटपुट नहीं है।
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