जब फ़ाइलनाम में रिक्त स्थान होता है, तो मैं खोज आदेश के आउटपुट को पार्स कैसे करूं?


12

जैसे लूप का उपयोग करना

for i in `find . -name \*.txt` 

टूट जाएगा अगर कुछ फ़ाइल नाम में रिक्त स्थान है।

इस समस्या से बचने के लिए मैं किस तकनीक का उपयोग कर सकता हूं?


1
ध्यान दें कि उनके फ़ाइल नाम में फाइलें भी नई हो सकती हैं। इसलिए वहाँ find -print0और है xargs -0
डैनियल बेक

जवाबों:


12

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

उस ने कहा, आप जो चाहते हैं वह लगभग करने का एक तरीका है:

oIFS=$IFS
IFS=$'\n'

find . -name '*.txt' | while read -r i; do
  # use "$i" with whatever you're doing
done

IFS=$oIFS

$iबाद में रिक्त स्थान की व्याख्या करने वाली अन्य चीजों से बचने के लिए, इसका उपयोग करते समय भी याद रखें । $IFSइसका उपयोग करने के बाद वापस सेट करना भी याद रखें , क्योंकि ऐसा न करने पर बाद में मनमुटाव हो जाएगा।

इसमें एक अन्य कैविएट संलग्न है: whileलूप के अंदर जो कुछ होता है वह सब- उपले में हो सकता है, आपके द्वारा उपयोग किए जा रहे सटीक शेल के आधार पर, इसलिए वैरिएबल सेटिंग्स बनी नहीं रह सकती हैं। forलूप संस्करण से बचा जाता है कि लेकिन कीमत पर कि, भले ही आप लागू $IFSसमाधान से बचने के मुद्दों के लिए रिक्त स्थान के साथ, आप मुसीबत अगर में मिल जाएगा findरिटर्न बहुत सारी फ़ाइलें।

कुछ बिंदु पर इस सब के लिए सही फिक्स शेल के बजाय पर्ल या पायथन जैसी भाषा में कर रहा है।


1
मुझे इन सब से बचने के लिए सिर्फ पायथन का उपयोग करने का विचार पसंद है।
स्कॉट सी विलसन

12

इसका उपयोग करें find -print0और इसे xargs -0अपने छोटे C प्रोग्राम में लिखें या अपने छोटे C प्रोग्राम में इसे पाइप करें। यह वही है -print0और -0इसके लिए आविष्कार किया गया था।

शैल स्क्रिप्ट उन में रिक्त स्थान के साथ फ़ाइल नाम को संभालने का सबसे अच्छा तरीका नहीं है: आप इसे कर सकते हैं, लेकिन यह क्लंकी हो जाता है।


मेरी मशीन पर काम करता है ^ टीएम!
mcandre

2

आप "आंतरिक क्षेत्र विभाजक" ( IFS) लूप तर्क विभाजन के लिए अंतरिक्ष की तुलना में कुछ और सेट कर सकते हैं , जैसे

ORIGIFS=${IFS}
NL='
'
IFS=${NL}
for i in $(find . -name '*.txt'); do
    IFS=${ORIGIFS}
    #do stuff
done
IFS=${ORIGIFS}

मुझे IFSलगता है कि इसके उपयोग के बाद रीसेट हो गया है, ज्यादातर क्योंकि यह अच्छा लग रहा है, मुझे लगता है। मैंने इसे नईलाइन पर सेट करने में कोई समस्या नहीं देखी है, लेकिन मुझे लगता है कि यह "क्लीनर" है।

एक अन्य विधि, इस बात पर निर्भर करती है कि आप आउटपुट से क्या करना चाहते हैं find, यह या तो सीधे कमांड के -execसाथ उपयोग करना है find, या इसका उपयोग करना -print0और इसमें पाइप करना है xargs -0। पहले मामले में findबच निकलने वाले फ़ाइल नाम का ध्यान रखता है। में -print0मामला है, findएक अशक्त विभाजक के साथ इसके उत्पादन प्रिंट, और फिर xargsइस पर विभाजित होता है। चूँकि किसी फ़ाइल नाम में वह चरित्र नहीं हो सकता (जिसे मैं जानता हूँ), यह हमेशा की तरह सुरक्षित है। यह ज्यादातर साधारण मामलों में उपयोगी होता है; और आमतौर पर एक पूर्ण forलूप के लिए एक बढ़िया विकल्प नहीं है ।


1

के find -print0साथ उपयोग कर रहा हैxargs -0

find -print0के साथ संयुक्त का उपयोग करना xargs -0कानूनी फ़ाइल नामों के खिलाफ पूरी तरह से मजबूत है, और सबसे अधिक उपलब्ध तरीकों में से एक है। उदाहरण के लिए, मान लें कि आप वर्तमान निर्देशिका में प्रत्येक PDF फ़ाइल की सूची चाहते हैं। आप लिख सकते हैं

$ find . -iname '*.pdf' -print0 | xargs -0 -n 1 echo

यह -iname '*.pdf'वर्तमान निर्देशिका ( .) और किसी भी उप-निर्देशिका में हर पीडीएफ (के माध्यम से ) मिलेगा , और उनमें से प्रत्येक को echoकमांड के तर्क के रूप में पास करेगा । क्योंकि हमने -n 1विकल्प निर्दिष्ट किया है, xargsकेवल एक समय में एक तर्क पास करेगा echo। अगर हम उस विकल्प को छोड़ देते, xargsतो जितना संभव हो उतने पास हो जाते echo। (आप echo short input | xargs --show-limitsदेख सकते हैं कि कमांड लाइन में कितने बाइट्स की अनुमति है।)

क्या करता xargsहै, बिल्कुल?

हम स्पष्ट रूप से xargsइसके इनपुट पर प्रभाव को देख सकते हैं - और -nविशेष रूप से प्रभाव - एक स्क्रिप्ट का उपयोग करके जो इसके तर्कों को अधिक सटीक तरीके से गूँजता है echo

$ cat > echoArgs.sh <<'EOF'
#!/bin/bash
echo "Number of arguments: $#"

[[ $# -eq 0 ]] && exit

for i in $(seq 1 $#); do
    echo "Arg $i: <$1>"
    shift
done
EOF

$ find . -iname '*.pdf' -print0 | xargs -0 ./echoArgs.sh
$ find . -iname '*.pdf' -print0 | xargs -0 -n 1 ./echoArgs.sh

ध्यान दें कि यह रिक्त स्थान और newlines को पूरी तरह से संभालता है,

$ touch 'A space-age
new line of vending machines.pdf'
$ find . -iname '*space*' -print0 | xargs -0 -n 1 ./echoArgs.sh

जो निम्नलिखित आम समाधान के साथ विशेष रूप से परेशानी होगी:

chmod +x ./echoArgs.sh
for file in $(ls *spacey*); do
  ./echoArgs.sh "$file"
done
टिप्पणियाँ

1

मैं bashबैशर्स से असहमत हूं , क्योंकि bash, * निक्स टूल सेट के साथ, फाइलों को संभालने में काफी माहिर हैं (जिनमें जिनके नाम व्हाट्सएप एम्बेडेड हैं)।

वास्तव में, findआपको कौन से फाइलों को प्रोसेस करने के लिए चुनने पर ठीक अनाज नियंत्रण प्रदान करता है ... बैश पक्ष पर, आपको वास्तव में केवल यह महसूस करने की आवश्यकता है कि आपको इसमें तार बनाना चाहिए bash words; आम तौर पर "दोहरे उद्धरण चिह्नों", या IFS का उपयोग करने वाले कुछ अन्य तंत्रों का उपयोग करके, या पाते हैं{}

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

IFS=$'\n' find ~/ -name '*.txt' -exec  function-or-util {} \;  

और, दो और उदाहरण

IFS=$'\n' find ~/ -name '*.txt' -exec  printf 'Hello %s\n' {} \;  
IFS=$'\n' find ~/ -name '*.txt' -exec  echo {} \+ |sed 's/home//'  

'खोजें also allows you to pass multiple filenames as args to you script ..(if it suits your need: use+ instead\; `)


1
दोनों दृष्टिकोणों के लिए कुछ वैधता है। जब मैं केवल अपनी फाइलों पर काम कर रहा था, तो मैं केवल उनके उपयोग और चिंता की बात नहीं करूंगा, क्योंकि मेरी फाइलों में उनके नाम में रिक्त स्थान (या कैरिज रिटर्न!) नहीं है। लेकिन जब आप अन्य लोगों की फ़ाइलों के साथ काम करना शुरू करते हैं, तो आपको अधिक मजबूत तकनीकों का उपयोग करना होगा।
स्कॉट सी विल्सन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.