फ़ाइलों की प्रतिलिपि बनाते समय तर्क सूची बहुत लंबी है


26

मैंने सिर्फ एक प्रश्न पूछा है कि मैं विशेष एक्सटेंशन की फाइलों को कैसे गिन सकता हूं। अब मैं cpइन फाइलों को एक नया बनाना चाहता हूं dir

मैं कोशिश कर रहा हूँ,

cp *.prj ../prjshp/

तथा

cp * | grep '\.prj$' ../prjshp/

लेकिन वे एक ही त्रुटि दे रहे हैं,

बैश: / बिन / सीपी: तर्क सूची बहुत लंबी है

मैं उनकी नकल कैसे करूं?


जवाबों:


36

cp *.prj ../prjshp/सही आदेश है, लेकिन आपने एक दुर्लभ मामला मारा है जहां यह एक आकार सीमा में चलता है। आपने जिस दूसरी कमांड की कोशिश की, उसका कोई मतलब नहीं है।

एक तरीका है cpचंक्स में फाइलों को चलाना । findआदेश जानता है ऐसा करने के तरीके:

find -maxdepth 1 -name '*.prj' -exec mv -t ../prjshp {} +
  • find वर्तमान निर्देशिका और इसके नीचे की निर्देशिकाओं को पुनरावृत्ति करता है।
  • -maxdepth 1 1 की गहराई पर रोकने का मतलब है, यानी उपनिर्देशिकाओं में पुनरावृत्ति न करें।
  • -name '*.prj'केवल उन फाइलों पर कार्य करने का मतलब है जिनका नाम निर्दिष्ट पैटर्न से मेल खाता है। पैटर्न के आसपास के उद्धरणों पर ध्यान दें: इसकी व्याख्या findकमांड द्वारा की जाएगी, शेल द्वारा नहीं।
  • -exec … {} +सभी फाइलों के लिए निर्दिष्ट कमांड निष्पादित करने का मतलब है। यदि आवश्यक हो, तो कमांड लाइन की सीमा से अधिक नहीं होने का ध्यान रखते हुए यह कमांड को कई बार लागू करता है।
  • mv -t ../prjshpनिर्दिष्ट फ़ाइलों में ले जाता है ../prjshp-tविकल्प की एक सीमा की वजह से यहाँ प्रयोग किया जाता है findआदेश: पाया फ़ाइलें (प्रतीक {}) आदेश के अंतिम तर्क के रूप में पारित कर रहे हैं, तो आप इसे बाद गंतव्य नहीं जोड़ सकते।

एक अन्य विधि का उपयोग करना है rsync

rsync -r --include='*.prj' --exclude='*' . ../prjshp
  • rsync -r … . ../prjshpवर्तमान निर्देशिका को ../prjshpपुनरावर्ती में कॉपी करता है ।
  • --include='*.prj' --exclude='*'फ़ाइलों को कॉपी करने *.prjऔर सब कुछ (उपनिर्देशिका सहित, इसलिए .prjउपनिर्देशिका में फाइलें नहीं मिलेंगी) को कॉपी करने का मतलब है ।

3
rsync, यहाँ अब तक का सबसे आसान समाधान है।
ntk4

कुछ निपुण होने के लिए, दूसरी कमांड का cp * | grep '\.prj$' ../prjshp/ कोई मतलब नहीं है, लेकिन एक सिंटैक्टिक रूप से मान्य हो सकता है, अगर *पिछले एक निर्देशिका (उर्फ cp SOURCE1 SOURCE2....DEST) होने के साथ फाइलों की सूची का विस्तार होता है । पाइप का कोई मतलब नहीं है, निश्चित रूप से, लेकिन यह भी सिंटैक्टिक रूप से मान्य रहता है जहां तक ​​शेल का संबंध है - यह dup()फाइल डिस्क्रिप्टर को ठीक करेगा, यह सिर्फ इतना है कि पाइप के रीडर एंड को कोई डेटा नहीं मिलेगा क्योंकि cpकोई भी लिखता नहीं है ।
सर्गी कोलोडियाज़नी

मेरे लिए rsync दोनों ने एक ही तर्क सूची का निर्माण किया है। लूप के लिए सबसे सरल समाधान था।
मिज़ान-उद-दीन

वास्तव में rsync किसी भी तरह की सामूहिक नकल करने का तरीका है, हालांकि मैं इस बात पर अडिग हूं कि हम लिनक्स से कितने दूर आ गए हैं और हमारे पास इस तरह एक मूर्खतापूर्ण दोष / बग है और हां मैं इसे दोष / बग मानूंगा।
मिशेल

22

यह कमांड एक-एक करके फाइलों को कॉपी करता है और तब भी काम करेगा जब उनमें से कई *एक ही cpकमांड में विस्तार के लिए हों :

for i in *; do cp "$i" ../prjshp/; done

यह मेरे लिए काम करता है।
1rq3fea324wre

1
सरल और प्रभावी। मेरे पास एक समान मुद्दा था ~ 1/4 मिलियन jpegs मैंने एक परियोजना के लिए एक वीडियो से निकाला था। यह वह दृष्टिकोण है जिसका मैंने उपयोग किया।
एल्डर गीक

5

Argument list too longत्रुटि का सामना करते समय ध्यान रखने के लिए 3 प्रमुख बिंदु हैं :

  • कमांड-लाइन तर्कों की लंबाई ARG_MAXचर द्वारा सीमित है , जो कि POSIX परिभाषा द्वारा "... [m] पर्यावरणीय डेटा सहित निष्पादन कार्यों के लिए तर्क की अधिकतम लंबाई है " (जोर जोड़ा) "। अर्थात, जब शेल एक गैर निष्पादित करता है। -बिल्ट-इट कमांड, इसमें से एक exec()को उस कमांड की प्रक्रिया को स्पॉन करने के लिए कॉल करना होता है, और ARG_MAXयहीं से प्ले में आता है। इसके अलावा, कमांड का नाम या पथ (उदाहरण के लिए, /bin/echo) एक भूमिका निभाता है।

  • शेल में निर्मित कमांड शेल द्वारा निष्पादित किए जाते हैं, जिसका अर्थ है कि शेल exec()फ़ंक्शन के परिवार का उपयोग नहीं करता है और इसलिए ARG_MAXचर से प्रभावित नहीं होता है ।

  • जैसे कि कुछ आदेश, xargsऔर findके बारे में पता कर रहे हैं ARG_MAXचर और बार बार है कि सीमा के अंतर्गत कार्रवाई करने

उपरोक्त बिंदुओं से और जैसा कि कुसलानंद के संबंधित प्रश्न पर उत्कृष्ट उत्तर में दिखाया गया है , Argument list too longपर्यावरण के बड़े होने पर भी हो सकता है। इसलिए यह ध्यान में रखते हुए कि प्रत्येक उपयोगकर्ता का वातावरण भिन्न हो सकता है, और बाइट्स में तर्क का आकार प्रासंगिक है, एक ही संख्या में फाइलों / तर्कों के साथ आना मुश्किल है।

ऐसी त्रुटि को कैसे संभालें?

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

शेल बिल्ट-इन का उपयोग करें

जैसा कि पहले चर्चा की गई है, शेल अंतर्निर्मित ARG_MAXसीमाएं प्रतिरक्षा हैं , जो कि forलूप, whileलूप, बिल्ट-इन echoऔर बिल्ट-इन जैसी चीजें हैं printf- वे सभी काफी अच्छा प्रदर्शन करेंगे।

for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done

फ़ाइलों को हटाने के बारे में संबंधित प्रश्न पर , इस तरह एक समाधान था:

printf '%s\0' *.jpg | xargs -0 rm --

ध्यान दें कि यह शेल के अंतर्निर्मित का उपयोग करता है printf। यदि हम बाहरी कॉल कर रहे हैं printf, तो इसमें शामिल होंगे exec(), इसलिए बड़ी संख्या में तर्क विफल होंगे:

$ /usr/bin/printf "%s\0" {1..7000000}> /dev/null
bash: /usr/bin/printf: Argument list too long

बैश सरण

जॉलीग्रे के एक उत्तर के अनुसार , bashसरणियों पर सीमाएं नहीं लगाई जाती हैं, इसलिए फ़ाइल नाम के स्लाइस का उपयोग करना और लूप के पुनरावृत्ति प्रति स्लाइस का उपयोग किया जा सकता है, जैसा कि danjpreron के उत्तर में दिखाया गया है :

files=( /path/to/old_dir/*.prj )
for((I=0;I<${#files[*]};I+=1000)); do 
    cp -t /path/to/new_dir/ "${files[@]:I:1000}" 
done

हालाँकि, इसे बैश-विशिष्ट और गैर-पॉसिक्स होने की सीमा है।

स्टैक स्पेस बढ़ाएं

कभी-कभी आप देख सकते हैं कि लोग स्टैक स्पेस को बढ़ाने का सुझाव देते हैं ulimit -s <NUM>; लिनक्स पर ARG_MAX मान प्रत्येक प्रोग्राम के लिए स्टैक स्पेस का 1 / 4th है, जिसका अर्थ है स्टैक स्पेस को आनुपातिक रूप से तर्क के लिए स्थान बढ़ाना।

# getconf reports value in bytes, ulimit -s in kilobytes
$ getconf ARG_MAX
2097152
$ echo $((  $(getconf ARG_MAX)*4 ))
8388608
$ printf "%dK\n" $(ulimit -s) | numfmt --from=iec --to=none
8388608
# Increasing stack space results in increated ARG_MAX value
$ ulimit -s 16384
$ getconf ARG_MAX
4194304

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

शेल से बचें

एक और तरीका है, का उपयोग करना है pythonया python3जो डिफ़ॉल्ट रूप से उबंटू के साथ आता है। अजगर + यहाँ-डॉक्टर का उदाहरण नीचे दिया गया है, मैं व्यक्तिगत रूप से फ़ाइलों की एक बड़ी निर्देशिका की प्रतिलिपि बनाने के लिए 40,000 वस्तुओं की रेंज में कहीं इस्तेमाल किया गया है:

$ python <<EOF
> import shutil
> import os
> for f in os.listdir('.'):
>    if os.path.isfile(f):
>         shutil.copy(f,'./newdir/')
> EOF

पुनरावर्ती ट्रैवर्सल्स के लिए, आप os.walk का उपयोग कर सकते हैं ।

यह भी देखें:


2

IMHO, फाइलों की भीड़ से निपटने के लिए इष्टतम उपकरण हैं findऔर xargs। देखते हैं man find। देखते हैं man xargsfind, इसके -print0स्विच के साथ , NULफ़ाइलनामों की एक- सूचीबद्ध सूची का उत्पादन करता है (फ़ाइलनाम में किसी भी वर्ण को निष्पादित NULया शामिल किया जा सकता है /) जो स्विच xargsका उपयोग करके समझता है -0xargsउसके बाद सबसे लंबे समय तक कमांड की अनुमति दी जाती है (सबसे फ़ाइलनाम, अंत में कोई आधा फ़ाइल नाम नहीं) और इसे निष्पादित करता है। xargsयह तब तक दोहराता है जब तक findकोई अधिक फ़ाइल नाम नहीं देता। भागो xargs --show-limits </dev/nullसीमाओं को देखने के।

अपनी समस्या को हल करने के लिए (और man cpखोजने के लिए जाँच करने के बाद --target-directory=):

find . -maxdepth 1 -type f -name '*.prj' -print0 | xargs -0 cp --target-directory=../prjshp/
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.