প্রচুর পরিমাণে ফাইলের সংমিশ্রণ


15

আমার কাছে 10,000 ডলার ফাইল ( res.1- res.10000) রয়েছে যার মধ্যে একটি কলাম এবং সমান সংখ্যক সারি রয়েছে। আমি যা চাই তা হ'ল সংক্ষেপে; কলাম অনুসারে সমস্ত ফাইল এক নতুন ফাইলে মার্জ করুন final.res। আমি ব্যবহার করে চেষ্টা করেছি:

paste res.*

তবে (যদিও এই ফলাফলের ফাইল একটি ছোট উপশাখা জন্য কাজ বলে মনে হয়, এই নিম্নলিখিত ত্রুটির দেয় যখন সম্পূর্ণ সেট সম্পাদনা: Too many open files

এটি করার জন্য অবশ্যই একটি 'সহজ' উপায় থাকতে হবে, তবে দুর্ভাগ্যক্রমে আমি ইউনিক্সে বেশ নতুন। আগাম ধন্যবাদ!

পিএস: আপনাকে (আমার একটি) ডেটা ফাইল (গুলি) দেখতে কেমন তা সম্পর্কে ধারণা দিতে:

0.5
0.5
0.03825
0.5
10211.0457
10227.8469
-5102.5228
0.0742
3.0944
...

আপনি কি আদেশটি --serialদিয়ে বিকল্পটি ব্যবহার করার চেষ্টা করেছেন paste?
শিবমস

@ শিভামস paste --serialফাইলগুলি কলাম-অনুসারে মার্জ করে না ...
স্টিফেন কিট

@ স্টেফেনকিট অপেক্ষা করুন আমি কিছুটা বিভ্রান্ত তার অর্থ কি আউটপুট ফাইলে প্রতিটি ফাইলের ডেটার জন্য আলাদা কলাম দরকার? বা একক কলামে সমস্ত তথ্য?
শিবমস

@ স্টেফেন কিট শিবামস ব্যবহার করে paste -sপ্রকৃতপক্ষে কাজ করে তবে কলাম- ওয়াইজের পরিবর্তে পৃথক ফলাফলের ফাইলগুলি সারিবদ্ধভাবে আটকান । যাইহোক, এটি এমন কিছু যা আমি সমাধান করতে পারি। ধন্যবাদ!
ম্যাট

@ শিভামস আমি আউটপুট ফাইলে প্রতিটি ফাইলের ডেটার জন্য একটি পৃথক কলাম চাই
ম্যাট

উত্তর:


17

যদি সেই মেশিনে আপনার কাছে রুট অনুমতি থাকে আপনি অস্থায়ীভাবে "সর্বাধিক সংখ্যক ওপেন ফাইল বর্ণনাকারীর সীমা" বাড়াতে পারেন:

ulimit -Hn 10240 # The hard limit
ulimit -Sn 10240 # The soft limit

এবং তারপর

paste res.* >final.res

এর পরে আপনি এটিকে আবার মূল মানগুলিতে সেট করতে পারেন।


একটি দ্বিতীয় সমাধান , আপনি সীমা পরিবর্তন করতে পারবেন না যদি:

for f in res.*; do cat final.res | paste - $f >temp; cp temp final.res; done; rm temp

এটি pasteপ্রতিটি ফাইলের জন্য একবার কল করে , এবং শেষে সমস্ত কলাম সহ একটি বিশাল ফাইল থাকে (এটি তার মিনিট নেয়)।

সম্পাদনা : বিড়ালের অকেজো ব্যবহার ... না !

মন্তব্যে উল্লিখিত হিসাবে catএখানে ( cat final.res | paste - $f >temp) এর ব্যবহার অকেজো নয়। প্রথমবার লুপটি চালায়, ফাইলটি final.resইতিমধ্যে বিদ্যমান নেই। pasteতারপরে ব্যর্থ হয় এবং ফাইলটি কখনও পূরণ হয় না, তৈরিও হয় না। আমার সমাধানটি কেবলমাত্র catপ্রথমবারের সাথে ব্যর্থ হয় No such file or directoryএবং pasteস্টিডিন থেকে খালি ফাইলটি পড়ে, তবে এটি অবিরত থাকে। ত্রুটি উপেক্ষা করা যেতে পারে।


ধন্যবাদ! কোনও ধারণা কীভাবে আমি আসল মানগুলি কী তা যাচাই করতে পারি?
ম্যাটগুলি

মাত্র ulimit -Sn নরম সীমাবদ্ধতার ulimit -Hnজন্য এবং কঠোর সীমাটির জন্য
বিশৃঙ্খলা

ধন্যবাদ, এটি আংশিকভাবে কাজ করে। তবে, ফাইল অন্য সেট আমি নিম্নলিখিত ত্রুটির পাবেন: -bash: /usr/bin/paste: Argument list too long। এর সমাধান কীভাবে করবেন? আপনাকে বলছি বিরক্ত করার জন্য দুঃখিত।
মাদুর

@ ফরমেটগুলি মনে হচ্ছে আপনার কার্নেল আরও আর্গুমেন্টের অনুমতি দেয় না, আপনি এটি পরীক্ষা করে getconf ARG_MAXদেখতে পারেন, কার্নেলটি পুনরায় সংশোধন করার সময় আপনি কেবল সেই মানটি বাড়াতে পারবেন। আপনি আমার দ্বিতীয় সমাধান চেষ্টা করতে পারেন?
বিশৃঙ্খলা

2
পরিবর্তে ব্যবহার catলুপের মাধ্যমে প্রতিবার , আপনি খালি final.resফাইল তৈরি করে শুরু করতে পারেন । ইতিমধ্যে কোনও final.resফাইল রয়েছে সে ক্ষেত্রে এটি সম্ভবত কোনওভাবেই ভাল ধারণা ।
বার্মার

10

যদি বিশৃঙ্খলা 'উত্তর প্রযোজ্য (কারণ প্রয়োজনীয় অনুমতি নেই) না হয় তবে আপনি ব্যাচ আপ করতে পারেন pasteকল নিম্নরূপ:

ls -1 res.* | split -l 1000 -d - lists
for list in lists*; do paste $(cat $list) > merge${list##lists}; done
paste merge* > final.res

এই তালিকা নামে ফাইলের মধ্যে একটি সময়ে 1000 ফাইল lists00, lists01ইত্যাদি, তারপর সংশ্লিষ্ট পেস্ট res.নামে ফাইল মধ্যে ফাইল merge00, merge01ইত্যাদি, এবং পরিশেষে সব আংশিকভাবে ফলে মার্জ ফাইল সংমিশ্রণে খেলা হয়।

বিশৃঙ্খলা দ্বারা উল্লিখিত হিসাবে আপনি একবারে ব্যবহৃত ফাইলের সংখ্যা বাড়িয়ে দিতে পারেন; সীমা হ'ল মানটি দেওয়া ulimit -nবিয়োগ তবে আপনার ইতিমধ্যে অনেকগুলি ফাইল খোলা রয়েছে, তাই আপনি বলবেন

ls -1 res.* | split -l $(($(ulimit -n)-10)) -d - lists

সীমা বিয়োগ দশ ব্যবহার করতে।

যদি আপনার সংস্করণটি splitসমর্থন না করে তবে -dআপনি এটিকে সরাতে পারেন: এটি splitসমস্তটি সংখ্যার প্রত্যয় ব্যবহার করার জন্য বলা হয়। ডিফল্টরূপে প্রত্যয় হতে হবে aa, abইত্যাদি পরিবর্তে 01, 02ইত্যাদি

যদি এখানে অনেকগুলি ফাইল ls -1 res.*ব্যর্থ হয় ("যুক্তির তালিকাগুলি খুব দীর্ঘ"), আপনি এটিকে প্রতিস্থাপন করতে পারেন findযা সেই ত্রুটিটি এড়াতে পারে:

find . -maxdepth 1 -type f -name res.\* | split -l 1000 -d - lists

( Don_crissti দ্বারা চিহ্নিত হিসাবে , -1পাইপিং করার সময় প্রয়োজন হবে নাls আউটপুট দেওয়ার ; তবে আমি যে ক্ষেত্রের lsসাথে সম্পর্কিত হয় সেগুলি পরিচালনা করতে আমি এটি রেখে দিচ্ছি -C।)


4

এটি এইভাবে কার্যকর করার চেষ্টা করুন:

ls res.*|xargs paste >final.res

আপনি ব্যাচটি বিভিন্ন ভাগে ভাগ করতে পারেন এবং এর মতো কিছু চেষ্টা করতে পারেন:

paste `echo res.{1..100}` >final.100
paste `echo res.{101..200}` >final.200
...

এবং শেষে চূড়ান্ত ফাইল একত্রিত করুন

paste final.* >final.res

@ রোমিও নিনভ আমার প্রথম প্রশ্নটিতে যেমন উল্লেখ করেছেন তেমনই ত্রুটি দেয়:Too many open files
ম্যাট

@ ফর্ম্যাটস, এই ক্ষেত্রে আপনি কি ব্যাচটিকে কিছু অংশে বিভক্ত করার কথা বিবেচনা করেছেন? আপনাকে ধারণা দেওয়ার জন্য আমার উত্তরটি সম্পাদনা করবে
রোমিও নিনভ 26'15

ডান, @ স্টেফেনকিট, আমি আমার উত্তরটি সম্পাদনা করছি
রোমিও নিনভ

অস্থায়ী ফাইলগুলি এড়ানোর জন্য, final.x00পাইপগুলি তৈরি করা বিবেচনা করুন - হয় নামকরণকৃত FIFOs হিসাবে, বা স্পষ্টতই, প্রক্রিয়া বিকল্প ব্যবহার করে (যদি আপনার শেল এটি সমর্থন করে - যেমন বাশ)) এটি হাতে লিখে মজাদার নয়, তবে এটি একটি মেকফাইলের পক্ষে উপযুক্ত।
টবির স্পিড

4
i=0
{ paste res.? res.?? res.???
while paste ./res."$((i+=1))"[0-9][0-9][0-9]
do :; done; } >outfile

আমি মনে করি না যে এটি এতটা জটিল you've আপনি ইতিমধ্যে ফাইলের নামগুলি অর্ডার করে কঠোর পরিশ্রম করেছেন। শুধু তাদের সব খুলুন না, সব।

অন্য উপায়:

pst()      if   shift "$1"
           then paste "$@"
           fi
set ./res.*
while  [ -n "${1024}" ] ||
     ! paste "$@"
do     pst "$(($#-1023))" "$@"
       shift 1024
done >outfile

... তবে আমি মনে করি এটি তাদের পিছনে চলে ... এটি আরও ভালভাবে কাজ করতে পারে:

i=0;  echo 'while paste \'
until [ "$((i+=1))" -gt 1023 ] &&
      printf '%s\n' '"${1024}"' \
      do\ shift\ 1024 done
do    echo '"${'"$i"'-/dev/null}" \'
done | sh -s -- ./res.* >outfile

এবং এখানে আরও একটি উপায় রয়েছে:

tar --no-recursion -c ./ |
{ printf \\0; tr -s \\0; }    |
cut -d '' -f-2,13              |
tr '\0\n' '\n\t' >outfile

এটি tarআপনার জন্য সমস্ত ফাইলকে নাল-ডিলিমিট স্ট্রিমে একত্রিত করতে, ফাইলের নাম ছাড়াও এর সমস্ত শিরোনাম মেটাডেটা পার্স করে এবং সমস্ত ফাইলের সমস্ত লাইনকে ট্যাবগুলিতে রূপান্তর করে। এটি প্রকৃত পাঠ্য-ফাইল হওয়াতে ইনপুটটির উপর নির্ভর করে - এর অর্থ প্রতিটি প্রান্তে ডাব্লু / একটি নতুন লাইন এবং ফাইলগুলিতে কোনও নাল-বাইট নেই। ওহ - এবং এটি ফাইলের নামের নিজেদের হচ্ছে সম্পর্কে newline মুক্ত উপর নির্ভর (যদিও যে গনুহ সঙ্গে প্রবলভাবে ঘাঁটা করা যেতে পারে tarএর --xformবিকল্প) । এই শর্তগুলি পূরণ করার পরে এটি কোনও সংখ্যক ফাইলের খুব ছোট কাজ করা উচিত - এবং tarএটি প্রায় সমস্তই করবে do

ফলাফলটি দেখতে লাইনের একটি সেট যা:

./fname1
C1\tC2\tC3...
./fname2
C1\tC2\t...

ইত্যাদি।

আমি প্রথমে 5 টি টেস্টফিল তৈরি করে এটি পরীক্ষা করেছি। আমি এখনই 10000 ফাইল জেনিংয়ের মতো অনুভব করি না, তাই আমি প্রত্যেকের জন্য কিছুটা বড় হয়েছি - এবং এটিও নিশ্চিত করেছিলাম যে ফাইলের দৈর্ঘ্য একটি বিরাট চুক্তির দ্বারা পৃথক। tarস্ক্রিপ্টগুলি পরীক্ষা করার সময় এটি গুরুত্বপূর্ণ becausetar নির্ধারিত দৈর্ঘ্যে ইনপুট আটকে দেবে - আপনি যদি কমপক্ষে কয়েকটি পৃথক দৈর্ঘ্যের চেষ্টা না করেন তবে আপনি কখনই জানতে পারবেন না যে আপনি কেবলমাত্র একটিটি পরিচালনা করবেন কিনা।

যাইহোক, পরীক্ষার ফাইলগুলির জন্য আমি করেছি:

for f in 1 2 3 4 5; do : >./"$f"
seq "${f}000" | tee -a [12345] >>"$f"
done

ls পরবর্তীকালে রিপোর্ট:

ls -sh [12345]
68K 1 68K 2 56K 3 44K 4 24K 5

... তাহলে আমি দৌড়ে গেলাম ...

tar --no-recursion -c ./ |
{ printf \\0; tr -s \\0; }|
cut -d '' -f-2,13          |
tr '\0\n' '\n\t' | cut -f-25

... কেবল প্রতি লাইনে প্রথম 25 টি ট্যাব-বিস্মিত ক্ষেত্রগুলি দেখানোর জন্য (কারণ প্রতিটি ফাইল একক লাইন - সেখানে অনেকগুলি রয়েছে ) ...

আউটপুটটি ছিল:

./1
1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25
./2
1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25
./3
1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25
./4
1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25
./5
1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25

4

এতে জড়িত ফাইলগুলির পরিমাণ, লাইন মাপ, ইত্যাদি দেওয়া, আমার মনে হয় এটি ডিফল্ট আকারের সরঞ্জামগুলি (অ্যাজক, সেড, পেস্ট, * ইত্যাদি) ছাড়িয়ে যাবে will

আমি এটির জন্য একটি ছোট প্রোগ্রাম তৈরি করব, এটিতে 10,000 টি ফাইল খোলা থাকবে না, বা দৈর্ঘ্যে কয়েক'শ হাজারের লাইন থাকবে না (10 টির 10,000 টি ফাইল (উদাহরণে লাইনটির সর্বাধিক আকার))। প্রতিটি ফাইল থেকে বাইটের সংখ্যা পড়ার জন্য এটির জন্য কেবলমাত্র 10,000 ডলার এর পূর্ণসংখ্যা প্রয়োজন requires অসুবিধাটি হ'ল এতে একটি ফাইল ডেস্ক্রিপ্টর রয়েছে, এটি প্রতিটি ফাইলের জন্য, প্রতিটি লাইনের জন্য পুনরায় ব্যবহৃত হয় এবং এটি ধীর হতে পারে।

সংজ্ঞা FILESএবং ROWSপ্রকৃত সঠিক মান পরিবর্তন করা উচিত নয়। আউটপুট মান আউটপুট প্রেরণ করা হয়।

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILES 10000 /* number of files */
#define ROWS 500    /* number of rows  */

int main() {
   int positions[FILES + 1];
   FILE *file;
   int r, f;
   char filename[100];
   size_t linesize = 100;
   char *line = (char *) malloc(linesize * sizeof(char));

   for (f = 1; f <= FILES; positions[f++] = 0); /* sets the initial positions to zero */

   for (r = 1; r <= ROWS; ++r) {
      for (f = 1; f <= FILES; ++f) {
         sprintf(filename, "res.%d", f);                  /* creates the name of the current file */
         file = fopen(filename, "r");                     /* opens the current file */
         fseek(file, positions[f], SEEK_SET);             /* set position from the saved one */
         positions[f] += getline(&line, &linesize, file); /* reads line and saves the new position */
         line[strlen(line) - 1] = 0;                      /* removes the newline */
         printf("%s ", line);                             /* prints in the standard ouput, and a single space */
         fclose(file);                                    /* closes the current file */
      }
      printf("\n");  /* after getting the line from each file, prints a new line to standard output */
   }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.