কেন বিড়াল x >> এক্স লুপ হয়?


17

নিম্নলিখিত বাশ কমান্ডগুলি একটি ইনফিন্ট লুপে যায়:

$ echo hi > x
$ cat x >> x

আমি অনুমান করতে পারি যে এটি স্টাডাউটে লেখা শুরু করার পরে catথেকে পড়তে থাকবে x। তবে বিভ্রান্তকর বিষয়টি হ'ল বিড়ালের নিজস্ব পরীক্ষার বাস্তবায়ন বিভিন্ন আচরণের প্রদর্শন করে:

// mycat.c
#include <stdio.h>

int main(int argc, char **argv) {
  FILE *f = fopen(argv[1], "rb");
  char buf[4096];
  int num_read;
  while ((num_read = fread(buf, 1, 4096, f))) {
    fwrite(buf, 1, num_read, stdout);
    fflush(stdout);
  }

  return 0;
}

আমি যদি চালাতে পারি:

$ make mycat
$ echo hi > x
$ ./mycat x >> x

এটি লুপ হয় না । এর আচরণ catএবং আমি stdoutপূর্বে ফ্লাশ করছি এই সত্যটি প্রদান করে freadআবারও বলা হয়ে থাকে, আমি এই সি কোডটি একটি চক্রের পড়া এবং লেখা চালিয়ে যেতে আশা করব।

এই দুটি আচরণ কীভাবে সামঞ্জস্যপূর্ণ? catউপরের কোডটি না করে কেন লুপগুলি ব্যাখ্যা করে কোন পদ্ধতিটি ?


এটি আমার জন্য লুপ করে। আপনি কি স্ট্রেস / ট্রসের অধীনে এটি চালানোর চেষ্টা করেছেন? আপনি কি সিস্টেম চালু?
স্টাফেন চেজেলাস

দেখে মনে হচ্ছে বিএসডি বিড়ালটির এই আচরণ রয়েছে এবং আমরা যখন এই জাতীয় কিছু চেষ্টা করি তখন জিএনইউ বিড়াল একটি ত্রুটি জানায়। এই উত্তরটি একই আলোচনা করেছে এবং আমি বিশ্বাস করি যে আপনি জিএসইউ বিড়াল রয়েছে এবং পরীক্ষার সময় ত্রুটি পেয়েছে আপনি বিএসডি বিড়ালটি ব্যবহার করছেন।
রমেশ

আমি ডারউইন ব্যবহার করছি। আমি ধারণাটি পছন্দ করি যা cat x >> xএকটি ত্রুটি সৃষ্টি করে; তবে এই আদেশটি কর্নিগান এবং পাইকের ইউনিক্স বইয়ে অনুশীলন হিসাবে প্রস্তাবিত।
টাইলার

3
catসম্ভবত স্টুডিওগুলির পরিবর্তে সিস্টেম কলগুলি ব্যবহার করে। স্টিডিও সহ, আপনার প্রোগ্রামটি ইওএফনেসকে ক্যাশে করছে। যদি আপনি 4096 বাইটের চেয়ে বড় কোনও ফাইল দিয়ে শুরু করেন তবে আপনি কি একটি অসীম লুপ পাবেন?
প্লটনিক নিকট

@ মার্কপ্লটনিক, হ্যাঁ! ফাইলটি 4k এর বেশি হলে সি কোড লুপ হয়। ধন্যবাদ, সম্ভবত এটিই সেখানে সম্পূর্ণ পার্থক্য।
টাইলার

উত্তর:


12

পুরানো আরএইচইএল সিস্টেমে আমি পেয়েছি, লুপ /bin/catহয় নাcat x >> xcat"বিড়াল: এক্স: ইনপুট ফাইল আউটপুট ফাইল" ত্রুটি বার্তা দেয়। আমি মূর্খ করতে /bin/catএই করে: cat < x >> x। আমি যখন আপনার কোডটি উপরে চেষ্টা করি তখন আমি আপনার বর্ণিত "লুপিং" পাই। আমি "ক্যাট" ভিত্তিক একটি সিস্টেম কলও লিখেছিলাম:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int
main(int ac, char **av)
{
        char buf[4906];
        int fd, cc;
        fd = open(av[1], O_RDONLY);
        while ((cc = read(fd, buf, sizeof(buf))) > 0)
                if (cc > 0) write(1, buf, cc);
        close(fd);
        return 0;
}

এই loops, খুব। এখানে কেবলমাত্র বাফারিং (স্ট্ডিও-ভিত্তিক "মাইকাট" এর বিপরীতে) কার্নেলের মধ্যে যা চলছে।

আমার মনে হয় যা ঘটছে তা ফাইল ডেস্ক্রিপ্টর 3 (এর ফলাফল open(av[1])) এর 0 টি ফাইলের মধ্যে একটি অফসেট রয়েছে ফাইলড বর্ণনাকারী 1 (স্টাডাউট) এর 3 টি অফসেট রয়েছে কারণ ">>" "ইনভোকিং শেলটি একটি lseek()করে catশিশু প্রক্রিয়াটি হস্তান্তর করার পূর্বে বর্ণনাকারী ফাইল করুন ।

একটি এরকম read()কিনা একটি stdio বাফারের মধ্যে বা কোন ধরণের, একটি প্লেইন char buf[]অগ্রগতি ফাইল বর্ননাকারী 3. একটা করছেন অবস্থানে write()অগ্রগতি ফাইল বর্ননাকারী 1. অবস্থান ঐ দুটি অফসেট বিভিন্ন নম্বর আছে। ">>" এর কারণে, ফাইল বর্ণনাকারী 1 এর সবসময় ফাইল ডেস্ক্রিপ্টরের অফসেটের চেয়ে বড় বা সমান একটি অফসেট থাকে So সুতরাং কোনও "বিড়ালের মতো" প্রোগ্রাম লুপ হয়ে যাবে, যদি না এটি কিছু অভ্যন্তরীণ বাফারিং করে। এটা সম্ভব, এমনকি সম্ভবত একটি একটি stdio বাস্তবায়ন FILE *(যা চিহ্ন ধরনের stdoutএবং fযা নিজের বাফার এতে আপনার কোডে)। অভ্যন্তরীণ বাফার ফো পূরণ fread()করার read()জন্য একটি সিস্টেম কল আসলেই করতে পারে f। এটি অভ্যন্তরের অভ্যন্তরে কোনও কিছু পরিবর্তন করতে পারে বা নাও পারে stdout। কলিং fwrite()উপরstdoutএর ভিতরে কিছু পরিবর্তন করতে পারে বা নাও পারে f। সুতরাং একটি স্টিডিও-ভিত্তিক "বিড়াল" লুপ নাও পারে। বা এটি হতে পারে। অনেক কুৎসিত, কুরুচিপূর্ণ লিবিসি কোড না পড়েই বলা শক্ত।

আমি straceআরএইচইএল cat- তে একটি করেছি - এটি কেবল উত্তরসূরি read()এবং write()সিস্টেম কলগুলি করে। কিন্তু একটি catএইভাবে কাজ করতে হবে না। mmap()ইনপুট ফাইলটিতে এটি সম্ভব হবে, তারপরেও write(1, mapped_address, input_file_size)। কার্নেলটি সমস্ত কাজ করত। অথবা আপনি sendfile()লিনাক্স সিস্টেমে ইনপুট এবং আউটপুট ফাইল বর্ণনাকারীদের মধ্যে একটি সিস্টেম কল করতে পারেন । পুরানো সানোস 4.x সিস্টেমগুলি মেমরি ম্যাপিং ট্রিকটি করার জন্য গুজব রইল, তবে আমি জানি না যে কেউ কখনও সেন্ডফিল-ভিত্তিক বিড়ালটি করেছে কিনা। উভয় ক্ষেত্রেই "লুপিং" ঘটবে না, উভয় হিসাবে write()এবং sendfile()একটি দৈর্ঘ্য-থেকে-স্থানান্তর প্যারামিটার প্রয়োজন।


ধন্যবাদ। ডারউইনে, দেখে মনে হচ্ছে freadকলটি কোনও ইওএফ পতাকা ক্যাশে করেছে যেমন মার্ক প্লটনিকের পরামর্শ ছিল। প্রমাণ: [১] ডারউইন বিড়াল পঠিত নয়, পঠিত ব্যবহার করে; এবং [2] ডারউইনের ভয়ঙ্কর কল __স্রেফিল যা fp->_flags |= __SEOF;কিছু ক্ষেত্রে সেট করে। [1] src.gnu-darwin.org/src/bin/cat/cat.c [2] opensource.apple.com/source/Libc/Libc-167/stdio.subproj/…
টাইলার

1
এটি দুর্দান্ত - গতকাল আমিই প্রথম এটিকে উত্সাহিত করেছি। এটি উল্লেখ করার মতো হতে পারে যে কেবলমাত্র পসিক্স -সংজ্ঞায়িত স্যুইচটি catহ'ল cat -u- আনবুফার্ডের জন্য u
মাইকজার্ভ

প্রকৃতপক্ষে, পতাকা >>সহ ওপেন () কল করে প্রয়োগ করা উচিত O_APPEND, যা প্রতিটি লেখার অপারেশনকে (পরমাণুগতভাবে) ফাইলের বর্তমান প্রান্তে লেখার আগে ফাইল বর্ণনাকারীর অবস্থান পড়ার আগে যা ছিল তা বিবেচনা করে না causes এই আচরণটি foo >> logfile & bar >> logfileসঠিকভাবে কাজ করার জন্য প্রয়োজনীয় , উদাহরণস্বরূপ - আপনি ধরে নিতে পারবেন না যে আপনার নিজের শেষ লেখার শেষের পরে অবস্থানটি এখনও ফাইলের শেষ।
এইচএমখোলম মনিকা

1

একটি আধুনিক বিড়াল বাস্তবায়ন (sunos-4.0 1988) পুরো ফাইলটি ম্যাপ করতে mmap () ব্যবহার করে এবং তারপরে এই স্পেসের জন্য 1x রাইটিং () কল করে। ভার্চুয়াল মেমরি যতক্ষণ না পুরো ফাইলটি ম্যাপ করতে দেয় ততক্ষণ এ জাতীয় বাস্তবায়ন লুপ হবে না।

অন্যান্য প্রয়োগের জন্য এটি ফাইলটি I / O বাফারের চেয়ে বড় কিনা তার উপর নির্ভর করে।


অনেক catবাস্তবায়ন তাদের আউটপুট বাফার করে না (-u )। যারা সবসময় লুপ হবে।
স্টাফেন চেজেলাস

সোলারিস 11 (সানোজ -5.11) ছোট ফাইলগুলির জন্য এমএমএপ () ব্যবহার করছে না বলে মনে হয় (কেবলমাত্র 32769 বাইট বড় বা তত উপরে ফাইলগুলির জন্য এটির অবলম্বন মনে হয়)।
স্টাফেন চেজেলাস

সঠিক -u সাধারণত ডিফল্ট হয়। এটি কোনও লুপ বোঝায় না কারণ একটি বাস্তবায়ন পুরো ফাইলাইজ পড়তে পারে এবং সেই বুফ দিয়ে কেবল একটি লিখতে পারে।
ছদ্মবেশে

সোলারিস বিড়াল কেবল তখনই লুপ করে যদি ফাইলসাইজ হয়> সর্বাধিক মানচিত্রের আকারে বা প্রাথমিক ফাইল অফসেটটি যদি হয়! = 0।
schily

সোলারিস ১১. দিয়ে আমি যা পর্যবেক্ষণ করি তা যদি প্রাথমিক অফসেট হয় তবে এটি একটি পঠন () লুপ করে! = 0 বা যদি ফাইলাইজ 0 এবং 32768 হয় তবে তার উপরে এটি একবারে ফাইলের 8MiB বৃহত অঞ্চলগুলি এমএম্যাপ করে এবং কখনই না এমনকি পাইব ফাইলগুলির জন্য () লুপগুলি পড়ার জন্য প্রত্যাবর্তন করা হয়েছে বলে মনে হচ্ছে (বিরল ফাইলে পরীক্ষিত)।
স্টাফেন চেজেলাস

0

বাশ পিটফিলসে যেমন লেখা আছে , আপনি কোনও ফাইল থেকে পড়তে এবং একই পাইপলাইনে এটি লিখতে পারবেন না।

আপনার পাইপলাইন কী করে তার উপর নির্ভর করে ফাইলটি ক্লোবার্বড হতে পারে (0 টি বাইট বা সম্ভবত আপনার অপারেটিং সিস্টেমের পাইপলাইন বাফারের আকারের সমান সংখ্যক বাইট), বা এটি উপলব্ধ ডিস্কের স্থানটি পূরণ না করা বা না পৌঁছানো পর্যন্ত বাড়তে পারে it আপনার অপারেটিং সিস্টেমের ফাইলের আকার সীমাবদ্ধতা বা আপনার কোটা ইত্যাদি

সমাধানটি হয় টেক্সট সম্পাদক বা অস্থায়ী পরিবর্তনশীল ব্যবহার করা।


-1

আপনার উভয়ের মধ্যে এক ধরণের রেসের শর্ত রয়েছে xcat(উদাঃ কোর্টিল ৮.২৩) এর কিছু বাস্তবায়ন নিষিদ্ধ:

$ cat x >> x
cat: x: input file is output file

যদি এটি সনাক্ত না করা হয় তবে আচরণটি অবশ্যই প্রয়োগের উপর নির্ভর করবে (বাফার আকার ইত্যাদি)।

আপনার কোডে, আপনি ফাইলটির শেষের সূচকটি সেট করা থাকলে পরবর্তীটি কোনও ত্রুটি ফিরে আসার ক্ষেত্রে এর clearerr(f);পরে একটি যুক্ত করার চেষ্টা করতে পারে ।fflushfread


দেখে মনে হচ্ছে যে একটি ভাল ওএসের একক থ্রেডের সাথে একই পঠন / লেখার আদেশগুলি চালিত একক প্রক্রিয়াটির জন্য নির্ধারিত আচরণ থাকবে। যাই হোক না কেন, আচরণটি আমার পক্ষে নির্বিচারক এবং আমি মূলত তারতম্য সম্পর্কে জিজ্ঞাসা করছি।
টাইলার

@ টাইলার আইএমএইচও, এই ক্ষেত্রে পরিষ্কার স্পষ্টতা ছাড়াই, উপরের কমান্ডটি কোনও অর্থ দেয় না, এবং নির্ধারণবাদটি সত্যই গুরুত্বপূর্ণ নয় (এখানকার মতো ত্রুটি ব্যতীত, যা সর্বোত্তম আচরণ)। এটি কিছুটা সি এর i = i++;অপরিজ্ঞাত আচরণের মতো, অতএব বৈষম্য।
ভিঙ্ক 17

1
না, এখানে কোনও রেসের শর্ত নেই, আচরণটি সঠিকভাবে সংজ্ঞায়িত। এটি ফাইলের আপেক্ষিক আকার এবং ব্যবহৃত বাফারের উপর নির্ভর করে বাস্তবায়ন-সংজ্ঞায়িত cat
গিলস 'অশুভ হওয়া বন্ধ করুন'

@ গিলস আপনি কোথায় দেখতে পাচ্ছেন যে আচরণটি ভাল সংজ্ঞাযুক্ত / বাস্তবায়ন-সংজ্ঞায়িত? আপনি কিছু রেফারেন্স দিতে পারেন? পসিক্স বিড়ালের স্পেসিফিকেশন কেবল বলেছে: "-যু বিকল্পটি নির্দিষ্ট না করা থাকলে বিড়ালের ইউটিলিটি বাফার আউটপুটটি প্রয়োগকরণ-সংজ্ঞায়িত" " তবে, যখন কোনও বাফার ব্যবহার করা হয়, বাস্তবায়নের ক্ষেত্রে এটি কীভাবে ব্যবহৃত হয় তা নির্ধারণ করতে হবে না; এটি অ-বিবাদী হতে পারে, যেমন এলোমেলো সময়ে ফ্লাশযুক্ত বাফার সহ।
ভিঙ্ক 17

@ vinc17 দয়া করে আমার আগের মন্তব্যে "অনুশীলনে" প্রবেশ করুন। হ্যাঁ, এটি তাত্ত্বিকভাবে সম্ভব এবং পসিক্স-অনুগত, তবে কেউ তা করেন না।
গিলস 'তাই খারাপ হওয়া বন্ধ করুন'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.