सही क्रम में एक साथ बहुत बड़ी संख्या में फाइलें कैट


23

मेरे पास लगभग 15,000 फाइलें हैं file_1.pdb, जिनका नाम है , file_2.pdbआदि। मैं इनमें से कुछ हजार के बारे में बिल्ली कर सकता हूं:

cat file_{1..2000}.pdb >> file_all.pdb

हालाँकि, अगर मैं 15,000 फ़ाइलों के लिए ऐसा करता हूं, तो मुझे त्रुटि मिलती है

-bash: /bin/cat: Argument list too long

मैंने इस समस्या को हल करते हुए देखा है find . -name xx -exec xxलेकिन यह उस आदेश को संरक्षित नहीं करेगा जिसके साथ फाइलें जुड़ती हैं। इसे कैसे प्राप्त किया जा सकता है?


3
दसवीं फाइल को क्या नाम दिया गया है? (या एक से अधिक अंकों वाली किसी भी फ़ाइल को क्रमबद्ध किया गया है।)
रोज़

I (अभी) के पास एक निर्देशिका में इनमें से 15,000 फाइलें हैं और आपका cat file_{1..15000}.pdbनिर्माण मेरे लिए ठीक काम करता है।
रोज़

11
सिस्टम पर निर्भर करता है कि सीमा क्या है। getconf ARG_MAXक्या बताना चाहिए।
ilkachachu

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

जवाबों:


49

उपयोग करना find, sortऔर xargs:

find . -maxdepth 1 -type f -name 'file_*.pdb' -print0 |
sort -zV |
xargs -0 cat >all.pdb

findआदेश सभी संबंधित फाइलों को पाता है, तो बाहर करने के लिए अपने pathnames प्रिंट sortहै कि एक "संस्करण तरह" उन्हें सही क्रम में प्राप्त करने के लिए करता है (यदि फ़ाइल नाम में संख्याओं किया गया था एक निश्चित करने के लिए शून्य से भरे चौड़ाई हम की जरूरत नहीं होती -V)। xargsसॉर्ट किए गए पथनामों की इस सूची को लेता है और catइन पर यथासंभव बड़े बैचों में चलता है।

यह तब भी काम करना चाहिए जब फ़ाइल नाम में नए वर्ण और रिक्त स्थान जैसे अजीब वर्ण हों। हम इनका उपयोग करने के लिए nul-terminated नाम देने के लिए उपयोग -print0करते हैं , और इनका उपयोग करते हैं । भी अपने झंडे के साथ शून्य-समाप्त नाम पढ़ता है ।findsortsort-zxargs-0

ध्यान दें कि मैं उस फ़ाइल का परिणाम लिख रहा हूं जिसका नाम पैटर्न से मेल नहीं खाता है file_*.pdb


उपरोक्त समाधान कुछ उपयोगिताओं के लिए कुछ गैर-मानक झंडे का उपयोग करता है। ये इन उपयोगिताओं के GNU कार्यान्वयन और कम से कम OpenBSD और macOS कार्यान्वयन द्वारा समर्थित हैं।

उपयोग किए जाने वाले गैर-मानक झंडे हैं

  • -maxdepth 1, findकेवल शीर्ष-सबसे निर्देशिका में प्रवेश करने के लिए, लेकिन कोई उपनिर्देशिका नहीं। POSIXly, का उपयोग करेंfind . ! -name . -prune ...
  • -print0, findआउटपुट शून्य-समाप्त पथनाम बनाने के लिए (यह POSIX द्वारा माना जाता था लेकिन अस्वीकार कर दिया गया था)। -exec printf '%s\0' {} +इसके बदले कोई उपयोग कर सकता है ।
  • -z, sortशून्य से समाप्त रिकॉर्ड लेने के लिए । कोई POSIX तुल्यता नहीं है।
  • -V, के बाद की sortतरह बनाने के लिए । कोई POSIX समतुल्य नहीं है, लेकिन फ़ाइल नाम के विशिष्ट भागों पर एक संख्यात्मक प्रकार द्वारा प्रतिस्थापित किया जा सकता है यदि फ़ाइलनाम में एक निश्चित उपसर्ग है।2003
  • -0, xargsपढ़ने के लिए शून्य से समाप्त रिकॉर्ड बनाने के लिए। कोई POSIX तुल्यता नहीं है। POSIXly, किसी को पहचानने वाले प्रारूप में फ़ाइल नामों को उद्धृत करने की आवश्यकता होगी xargs

Pathnames अच्छी तरह व्यवहार कर रहे हैं, और यदि निर्देशिका संरचना फ्लैट (कोई उपनिर्देशिका) है, तो एक को छोड़कर इन झंडे के बिना करते हैं, कर सकते हैं -Vके साथ sort


1
इसके लिए आपको अमानक अशक्त समाप्ति की आवश्यकता नहीं है। ये फ़ाइल नाम अत्यधिक उबाऊ हैं और POSIX उपकरण तब पूरी तरह से निपटने में सक्षम हैं।
केविन

6
तुम भी रूप में प्रश्नकर्ता के विनिर्देश के साथ और अधिक संक्षेप लिख सकते printf ‘file_%d.pdb\0’ {1..15000} | xargs -0 cat, या यहाँ तक, केविन के दृष्टिकोण से echo file_{1..15000}.pdb | xargs catfindसमाधान काफी अधिक भूमि के ऊपर के बाद से यह उन फ़ाइलों के लिए फाइल सिस्टम खोज करने के लिए है, लेकिन यह अधिक उपयोगी है जब फ़ाइलों में से कुछ मौजूद नहीं हो सकता है।
कोजीरो

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

1
@chrylis एक पुनर्निर्देशन एक कमांड के तर्कों का हिस्सा नहीं है, और यह इसके xargsबजाय catपुनर्निर्देशित है (प्रत्येक catमंगलाचरण xargsमानक आउटपुट का उपयोग करेगा )। अगर हमने कहा होता, xargs -0 sh -c 'cat >all.pdb'तो इसका उपयोग >>करने के बजाय >, अगर आप इशारा कर रहे होते, तो इसका अर्थ होता ।
Kusalananda

1
ऐसा लगता है कि sort -n -k1.6यह काम करेगा (मूल, file_nnnफ़ाइलनाम के लिए, या sort -n -k1.5बिना अंडरस्कोर वाले लोगों के लिए)।
स्कॉट

14

के साथ zsh(जहां वह {1..15000}ऑपरेटर आता है):

autoload zargs # best in ~/.zshrc
zargs file_{1..15000}.pdb -- cat > file_all.pdb

या file_<digits>.pdbसंख्यात्मक क्रम में सभी फाइलों के लिए :

zargs file_<->.pdb(n) -- cat > file_all.pdb

(जहाँ <x-y>एक ग्लोब ऑपरेटर है जो दशमलव संख्या x से y पर मेल खाता है। xना के साथ, ना ही yयह कोई दशमलव संख्या है। extendedglob's [0-9]##या kshglob' s +([0-9])(एक या अधिक अंक) के बराबर है ।)

ksh93अपनी अंतर्निहित catकमांड का उपयोग करने के साथ (ताकि execve()सिस्टम कॉल की उस सीमा से प्रभावित न हो क्योंकि वहाँ कोई निष्पादन नहीं है ):

command /opt/ast/bin/cat file_{1..15000}.pdb > file_all.pdb

साथ bash/ zsh/ ksh93(समर्थन जो zshकी {x..y}और printfनिर्मित):

printf '%s\n' file_{1..15000}.pdb | xargs cat > file_all.pdb

GNU सिस्टम या संगत पर, आप भी उपयोग कर सकते हैं seq:

seq -f 'file_%.17g.pdb' 15000 | xargs cat > file_all.pdb

के लिए xargsआधारित समाधान, विशेष देखभाल की फ़ाइल नाम है कि रिक्त स्थान, एकल या डबल उद्धरण या बैकस्लैश शामिल के लिए ले जाया जा रहा होगा।

के लिए की तरह -It's a trickier filename - 12.pdb, उपयोग करें:

seq -f "\"./-It's a trickier filename - %.17g.pdb\"" 15000 |
  xargs cat > file_all.pdb

seq -f | xarg cat > सबसे सुंदर, और प्रभावी समाधान है। (IMHO)।
हस्त्तूर

चालबाज फ़ाइल नाम की जाँच करें ... हो सकता है '"./-It'\''s a trickier filename - %.17g.pdb"'?
Hastur

@ हस्तूर, उफ़! हाँ, धन्यवाद, मैंने इसे एक वाक्यविन्यास उद्धृत विकल्प में बदल दिया है। तुम्हारा भी काम होगा।
स्टीफन चेज़लस

11

लूप के लिए संभव है, और बहुत सरल है।

for i in file_{1..15000}.pdb; do cat $i >> file_all.pdb; done

नकारात्मक पक्ष यह है कि आप catबहुत बार नरक का आह्वान करते हैं। लेकिन अगर आपको ठीक से याद नहीं है कि सामान को किस तरह से करना है findऔर इनवोकेशन ओवरहेड आपकी स्थिति में बहुत बुरा नहीं है, तो यह ध्यान में रखने योग्य है।


मैं अक्सर echo $i;लूप बॉडी में "प्रगति सूचक" के रूप में जोड़ता हूं
रॉल्फ

3
seq 1 15000 | awk '{print "file_"$0".dat"}' | xargs cat > file_all.pdb

1
awk यहाँ seq के काम कर सकते हैं और seq awk का काम कर सकते हैं: seq -f file_%.10g.pdb 15000। ध्यान दें कि seqएक मानक कमांड नहीं है।
स्टीफन चेज़लस

धन्यवाद स्टीफन - मुझे लगता seq -f है कि यह करने का एक शानदार तरीका है; याद होगा कि
लैरीक

2

परिसर

आपको उस त्रुटि में उस विशिष्ट नाम प्रारूप [ 1 , 2 ] के साथ केवल 15k फ़ाइलों के लिए नहीं उठाना चाहिए ।

यदि आप उस विस्तार को किसी अन्य निर्देशिका से चला रहे हैं और आपको प्रत्येक फ़ाइल में पथ जोड़ना है, तो आपकी कमांड का आकार बड़ा होगा, और निश्चित रूप से यह हो सकता है।

समाधान उस निर्देशिका से कमांड चलाते हैं।

(cd That/Directory ; cat file_{1..2000}.pdb >> file_all.pdb )

सर्वश्रेष्ठ समाधान यदि इसके बजाय मैंने खराब अनुमान लगाया है और आप इसे उस निर्देशिका से चलाते हैं जिसमें फाइलें हैं ...
IMHO सबसे अच्छा समाधान स्टीफन चेज़ेलस हैं :

seq -f 'file_%.17g.pdb' 15000 | xargs cat > file_all.pdb

प्रिंटफ या सीक के साथ; प्री-कैशेड के अंदर केवल उनकी संख्या के साथ 15k फाइलों पर परीक्षण किया गया है यह और भी तेज है (वर्तमान में और ओपी एक को छोड़कर उसी निर्देशिका से जिसमें फाइलें हैं)।

कुछ शब्द और

आपको अपनी शेल कमांड लाइनों को और अधिक लंबा करने में सक्षम होना चाहिए।
आपकी कमांड लाइन 213914 वर्ण लंबी है और इसमें 15003 शब्द हैं
cat file_{1..15000}.pdb " > file_all.pdb" | wc

... यहां तक ​​कि प्रत्येक शब्द के लिए 8 बाइट्स जोड़ने पर 333 938 बाइट्स (0.3M) 2097142 (2.1M) से नीचे ARG_MAXकर्नेल पर 3.13.0 या थोड़ा छोटे 2088232 द्वारा रिपोर्ट की गई "कमांड की अधिकतम लंबाई" के रूप में रिपोर्ट किया गया है। का उपयोग करें " द्वाराxargs --show-limits

के उत्पादन के लिए अपने सिस्टम पर एक नजर डालें

getconf ARG_MAX
xargs --show-limits

आलस्य निर्देशित समाधान

इस तरह के मामलों में मैं ब्लॉक के साथ भी काम करना पसंद करता हूं क्योंकि आमतौर पर एक समय कुशल समाधान निकलता है।
तर्क (यदि कोई है) तो मैं 1 ... 1000 1001..2000 इत्यादि लिखने के लिए बहुत आलसी
हूं । इसलिए मैं एक स्क्रिप्ट को मेरे लिए करने के लिए कहता हूं।
आउटपुट की जाँच करने के बाद ही मैं इसे स्क्रिप्ट में रीडायरेक्ट करता हूँ।

... लेकिन आलस्य मन की एक अवस्था है
चूंकि मुझे एलर्जी है xargs(मुझे वास्तव में xargsयहां इस्तेमाल करना चाहिए ) और मैं यह नहीं जांचना चाहता कि इसका उपयोग कैसे करना है, मैं समय-समय पर पहिया को फिर से मजबूत करने के लिए समाप्त करता हूं जैसा कि नीचे दिए गए उदाहरणों में है (टीएल; ड्र)।

ध्यान दें कि चूंकि फ़ाइल नाम नियंत्रित हैं (कोई रिक्त स्थान, newlines ...) आप नीचे दी गई स्क्रिप्ट जैसी किसी चीज़ के साथ आसानी से जा सकते हैं।

tl; डॉ

संस्करण 1: 1 फ़ाइल नंबर, अंतिम, ब्लॉक आकार, आउटपुट फ़ाइल के वैकल्पिक पैरामीटर के रूप में पास करें

#!/bin/bash
StartN=${1:-1}          # First file number
EndN=${2:-15000}        # Last file number
BlockN=${3:-100}        # files in a Block 
OutFile=${4:-"all.pdb"} # Output file name

CurrentStart=$StartN 
for i in $(seq $StartN $BlockN $EndN)
do 
  CurrentEnd=$i ;  
    cat $(seq -f file_%.17g.pdb $CurrentStart $CurrentEnd)  >> $OutFile;
  CurrentStart=$(( CurrentEnd + 1 )) 
done
# Here you may need to do a last iteration for the part cut from seq
[[ $EndN -ge $CurrentStart ]] && 
    cat $(seq -f file_%.17g.pdb $CurrentStart $EndN)  >> $OutFile;

संस्करण 2

विस्तार के लिए बैश कॉलिंग (मेरे परीक्षणों में थोड़ा धीमा ~ 20%)।

#!/bin/bash
StartN=${1:-1}          # First file number
EndN=${2:-15000}        # Last file number
BlockN=${3:-100}        # files in a Block 
OutFile=${4:-"all.pdb"} # Output file name

CurrentStart=$StartN 
for i in $(seq $StartN $BlockN $EndN)
do 
  CurrentEnd=$i ;
    echo  cat file_{$CurrentStart..$CurrentEnd}.pdb | /bin/bash  >> $OutFile;
  CurrentStart=$(( CurrentEnd + 1 )) 
done
# Here you may need to do a last iteration for the part cut from seq
[[ $EndN -ge $CurrentStart ]] && 
    echo  cat file_{$CurrentStart..$EndN}.pdb | /bin/bash  >> $OutFile;

बेशक आप आगे जा सकते हैं और पूरी तरह से seq [ 3 ] से छुटकारा पा सकते हैं (कोर्यूटिल्स से) और सीधे बैश में चर के साथ काम करते हैं, या अजगर का उपयोग करते हैं, या एसी प्रोग्राम को करने के लिए [ 4 ] ...


ध्यान दें कि के %gलिए कम है %.6g। यह उदाहरण के लिए 1e + 06 के रूप में 1,000,000 का प्रतिनिधित्व करेगा।
स्टीफन चेज़लस

वास्तव में आलसी लोगों के आसपास काम करने के कार्य के लिए तैयार किया गया है उपकरणों का उपयोग इस तरह E2BIG सीमा xargszsh के, zargsया ksh93की command -x
स्टीफन चेज़लस

seqबैश बिलिन नहीं है, यह GNU कोरुटिल्स से एक कमांड है। seq -f %g 1000000 1000000Coreeils के नवीनतम संस्करण में भी 1e + 06 आउटपुट।
स्टीफन चेज़लस

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

@ स्टीफनचैलेजेलस गोत्चा, राइट ... फिक्स्ड। धन्यवाद। मैंने केवल ओपी द्वारा दी गई 15k फाइलों के साथ परीक्षण किया, मेरी खराब।
हस्त्तूर

0

इसे करने का एक और तरीका हो सकता है

(cat file_{1..499}.pdb; cat file_{500..999}.pdb; cat file_{1000..1499}.pdb; cat file_{1500..2000}.pdb) >> file_all.pdb
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.