আমি কেন এই ব্যাশ পাইপ নির্মাণ ব্যবহার করে ডেটা হারাতে চাইছি?


11

আমি এর মতো কয়েকটি প্রোগ্রাম একত্রিত করার চেষ্টা করছি (দয়া করে কোনও অতিরিক্ত অন্তর্ভুক্ত উপেক্ষা করুন, এটি ভারী কাজ চলছে):

pv -q -l -L 1  < input.csv | ./repeat <(nc "host" 1234)

যেখানে পুনরাবৃত্তি প্রোগ্রামের উত্সটি নীচে দেখায়:

#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <iostream>
#include <string>

inline std::string readline(int fd, const size_t len, const char delim = '\n')
{
    std::string result;
    char c = 0;
    for(size_t i=0; i < len; i++)
    {
        const int read_result = read(fd, &c, sizeof(c));
        if(read_result != sizeof(c))
            break;
        else
        {
            result += c;
            if(c == delim)
                break;
        }
    }
    return result;
}

int main(int argc, char ** argv)
{
    constexpr int max_events = 10;

    const int fd_stdin = fileno(stdin);
    if (fd_stdin < 0)
    {
        std::cerr << "#Failed to setup standard input" << std::endl;
        return -1;
    }


    /* General poll setup */
    int epoll_fd = epoll_create1(0);
    if(epoll_fd == -1) perror("epoll_create1: ");
    {
        struct epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = fd_stdin;
        const int result = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_stdin, &event);
        if(result == -1) std::cerr << "epoll_ctl add for fd " << fd_stdin << " failed: " << strerror(errno) << std::endl;
    }

    if (argc > 1)
    {
        for (int i = 1; i < argc; i++)
        {
            const char * filename = argv[i];
            const int fd = open(filename, O_RDONLY);
            if (fd < 0)
                std::cerr << "#Error opening file " << filename << ": error #" << errno << ": " << strerror(errno) << std::endl;
            else
            {
                struct epoll_event event;
                event.events = EPOLLIN;
                event.data.fd = fd;
                const int result = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);
                if(result == -1) std::cerr << "epoll_ctl add for fd " << fd << "(" << filename << ") failed: " << strerror(errno) << std::endl;
                else std::cerr << "Added fd " << fd << " (" << filename << ") to epoll!" << std::endl;
            }
        }
    }

    struct epoll_event events[max_events];
    while(int event_count = epoll_wait(epoll_fd, events, max_events, -1))
    {
        for (int i = 0; i < event_count; i++)
        {
            const std::string line = readline(events[i].data.fd, 512);                      
            if(line.length() > 0)
                std::cout << line << std::endl;
        }
    }
    return 0;
}

আমি এটি লক্ষ্য করেছি:

  • আমি যখন পাইপটি কেবল ব্যবহার করি তখন ./repeatসমস্ত কিছুই ইচ্ছাকৃতভাবে কাজ করে।
  • আমি যখন কেবল প্রক্রিয়া প্রতিস্থাপন ব্যবহার করি তখন সমস্ত কিছু উদ্দেশ্য হিসাবে কাজ করে।
  • আমি যখন প্রক্রিয়া প্রতিস্থাপন ব্যবহার করে পিভিকে encapsulate করি তখন সমস্ত কিছু উদ্দেশ্য হিসাবে কাজ করে।
  • তবে, যখন আমি নির্দিষ্ট নির্মাণ ব্যবহার করি, আমি স্টিডিনের ডেটা (স্বতন্ত্র অক্ষরগুলি) হারিয়ে ফেলব বলে মনে হয়!

আমি নিম্নলিখিত চেষ্টা করেছি:

  • আমি পাইপটিতে বাফারিং নিষ্ক্রিয় করার চেষ্টা করেছি pvএবং সমস্ত প্রক্রিয়া ./repeatব্যবহার করেছিলাম stdbuf -i0 -o0 -e0, তবে এটি কার্যকর হবে বলে মনে হয় না।
  • আমি জরিপের জন্য এপল পরিবর্তন করেছি, কাজ করে না।
  • আমি যখন pvএবং এর ./repeatসাথে প্রবাহটি দেখি তখন এটি tee stream.csvসঠিক দেখাচ্ছে।
  • আমি যা দেখছিলাম straceতা দেখতে পেয়েছি এবং আমি প্রচুর একক বাইট পড়ে দেখলাম (যেমনটি প্রত্যাশা করা হয়েছিল) এবং তারা এও দেখায় যে ডেটা হারিয়ে যাচ্ছে।

আমি ভাবছি কি হচ্ছে? বা আরও তদন্ত করতে আমি কী করতে পারি?

উত্তর:


16

কারণ ncভিতরে কমান্ডটি <(...)স্টিডিন থেকেও পড়বে।

সহজ উদাহরণ:

$ nc -l 9999 >/tmp/foo &
[1] 5659

$ echo text | cat <(nc -N localhost 9999) -
[1]+  Done                    nc -l 9999 > /tmp/foo

কোথায় গেল text? নেটকাটের মাধ্যমে।

$ cat /tmp/foo
text

আপনার প্রোগ্রাম এবং ncএকই স্টিডিনের জন্য প্রতিযোগিতা করুন এবং এর ncকিছু পান।


তুমি ঠিক বলছো! ধন্যবাদ! আপনি কি স্ট্যান্ডিনকে সংযোগ বিচ্ছিন্ন করার জন্য কোনও পরিষ্কার উপায়ের পরামর্শ দিতে পারেন <(...)? এর চেয়েও সুন্দর উপায় আছে <( 0<&- ...)?
রোল বার্ডম্যান

5
<(... </dev/null)। ব্যবহার করবেন না 0<&-: এটি প্রথম নতুন এফডি হিসাবে open(2)ফিরে আসবে 0। যদি ncএটি সমর্থন করে তবে আপনি -dবিকল্পটিও ব্যবহার করতে পারেন ।
মশবী

3

ইপল () বা পোল () ই / পলিনের সাথে প্রত্যাবর্তন কেবল আপনাকে বলবে যে একটি একক পঠন () অবরুদ্ধ নাও হতে পারে

এমনটি নয় যে আপনি যেমনটি করেন তেমন একটি নিউলাইন পর্যন্ত অনেকগুলি বাইট রিড () গুলি করতে সক্ষম হবেন।

আমি বলতে may কারণ একটি পঠিত () epoll পর () ই সঙ্গে ফিরে / POLLIN এখনও অবরোধ করতে পারেন।

আপনার কোডটি অতীতের EOF পড়ার চেষ্টা করবে এবং কোনও পঠিত () ত্রুটি সম্পূর্ণ উপেক্ষা করবে ores


এটি আমার সমস্যার সরাসরি সমাধান না হয়েও মন্তব্যটি করার জন্য ধন্যবাদ। আমি বুঝতে পারি যে এই কোডটির ত্রুটি রয়েছে এবং ইওএফ সনাক্তকরণটি একটি কম স্ট্রিপড ডাউন সংস্করণে উপস্থিত রয়েছে (পলহাপ / পলএনভাল ব্যবহারের মাধ্যমে)। যদিও আমি একাধিক ফাইল বর্ণনাকারীর কাছ থেকে লাইন পড়ার জন্য একটি অসমাপ্ত উপায় খুঁজে বের করার সাথে লড়াই করি। আমার repeatপ্রোগ্রামটি মূলত একাধিক উত্স থেকে এনএমইএ ডেটা (লাইন-ভিত্তিক এবং কোনও দৈর্ঘ্যের সূচক ছাড়াই) প্রক্রিয়াকরণ করছে। যেহেতু আমি একাধিক লাইভ উত্স থেকে ডেটা একত্রিত করছি, তাই আমি চাই আমার সমাধানটি অশুভ করা হোক। আপনি কি আরও কার্যকর উপায় এটি করার পরামর্শ দিতে পারেন?
রোল বার্ডম্যান

fww, প্রতিটি বাইটের জন্য একটি সিস্টেম কল করা (পড়ুন) সম্ভব সবচেয়ে কম দক্ষ উপায়। ইওএফ চেকিং কেবল পঠনের রিটার্নের মান পরীক্ষা করেই করা যেতে পারে, পলহাপের দরকার নেই (এবং পোলএনওয়াল কেবল তখনই ফিরে আসবে যখন আপনি এটি বগাস এফডি পাস করবেন, ইওএফ-তে নয়)) তবে যাইহোক, থাকুন। আমার কাছে এমন একটি ypeeইউটিলিটির ধারণা রয়েছে যা একাধিক এফডিএস থেকে পড়ে এবং অন্য একটি এফডিতে মিশ্রিত করে রেকর্ড সংরক্ষণ করে (রেখাগুলি অক্ষত রাখে)।
এপ্রিজ নির্বাচন করুন

আমি লক্ষ্য করেছি যে এই বাশ নির্মাণটি এটি করা উচিত, তবে আমি জানি না কীভাবে এটিতে স্ট্ডিন একত্রিত করা যায়: ফাইলটিতে আপনি { cmd1 & cmd2 & cmd3; } > fileযা বর্ণনা করবেন তা থাকবে। তবে, আমার ক্ষেত্রে আমি tcpserver (3) থেকে সমস্ত কিছু চালাচ্ছি, তাই আমি স্টিডিনকেও অন্তর্ভুক্ত করতে চাই (এতে ক্লায়েন্টের ডেটা রয়েছে)। আমি কীভাবে করব তা নিশ্চিত নই।
রোল বার্ডম্যান

1
এটি সেমিডি 1, সেমিডি 2, ... কিসের উপর নির্ভর করে। যদি তারা এনসি বা বিড়াল এবং আপনার ডেটা লাইন-ভিত্তিক হয় তবে আউটপুটটি ত্রুটিযুক্ত হতে পারে - আপনি লাইনগুলি সেমিডি 1 দ্বারা মুদ্রিত একটি লাইনের শুরু এবং সেন্টিমিডি 2 দ্বারা মুদ্রিত একটি রেখার সমাপ্তি সহ মিলবে get
pizdelect
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.