как преобразовать скрипт bash в C ++ с помощью boost :: iostreams

Я пытаюсь преобразовать следующий код bash в C ++ с помощью boost :: iostreams:

#!/usr/bin/bash
(
    gzip -cd file1.ext.gz
    cat file2.ext
) | grep '^regex' # or sed 's/search/replace/'

Я могу открыть файл и распаковать его:

std::ifstream s("file.ext.gz", std::ios_base::in | std::ios_base::binary);
boost::iostreams::filtering_istreambuf in;
in.push(boost::iostreams::gzip_decompressor());
in.push(s);

Затем откройте несжатый файл:

std::ifstream s2("file.ext", std::ios_base::in | std::ios_base::binary);

Теперь я немного застрял, поэтому вот мои вопросы:

1) Какое решение boost :: iostreams для объединения двух потоков?

2) Как вывести результат через фильтр регулярных выражений для эмуляции grep / sed?

В результате я хотел бы иметь istream, который я могу скопировать в cout:

boost::iostream::copy(result, std::cout);

ОБНОВЛЕНИЕ полного решения с использованием конкатенации Хамигаки:

/*
 * convert the following bash script into C++
 *
 * #!/bin/bash
 * (
 *     gzip -cd file1.ext.gz
 *     cat file2.ext
 * ) | grep '^filter' | 'sed s/search/replace/g'
 *
 */

#include <iostream>
#include <boost/bind.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filter/regex.hpp>
#include <boost/iostreams/filter/grep.hpp>
#include <boost/iostreams/copy.hpp>

// http://hamigaki.sourceforge.jp/hamigaki/iostreams/concatenate.hpp
#include "concatenate.hpp"

namespace io = boost::iostreams;

int main(int argc, char const* argv[])
{
    io::file_source file1("file1.ext.gz");
    io::file_source file2("file2.ext");
    io::gzip_decompressor gzip;
    io::regex_filter sed(boost::regex("search"), "replace");
    io::grep_filter grep(boost::regex("^filter"));

    io::filtering_istreambuf in1(gzip | file1);
    io::filtering_istreambuf in2(file2);

    io::filtering_istreambuf combined(sed | grep | 
            hamigaki::iostreams::concatenate(
                boost::ref(in1),
                boost::ref(in2)
            )
        );

    io::copy(combined, std::cout);

    return 0;
}

person chris    schedule 21.02.2011    source источник
comment
Что касается оболочки, знаете ли вы о zgrep (если, конечно, вам не нужно, чтобы файл был несжатым)? Разве ваш сценарий не отправит файл grep дважды?   -  person Dennis Williamson    schedule 22.02.2011
comment
@Dennis: Я думаю, вы неправильно прочитали сценарий bash. У меня есть два файла, один из которых сжат, и я хочу объединить их вместе и найти (/ заменить) шаблон в результате.   -  person chris    schedule 22.02.2011
comment
Извините, я видел file.ext.gz и file.ext и решил, что второе было результатом первого (я упустил -c). Было бы яснее, если бы вы сказали file1.ext.gz и file2.ext.   -  person Dennis Williamson    schedule 22.02.2011
comment
@ Деннис: Понятно. Я соответствующим образом отредактировал вопрос. Извините за путаницу.   -  person chris    schedule 22.02.2011


Ответы (2)


1) Не знаю, встроено ли что-нибудь в boost, но этот класс кажется именно тем, что вам нужно: http://hamigaki.sourceforge.jp/hamigaki/iostreams/concatenate.hpp

Загвоздка здесь в том, что он ожидает, что устройства CopyConstructible будут объединяться, а цепочки, похоже, не будут CopyConstructible. Однако мы можем легко обойти это, используя boost :: ref. Этот код делает (почти) то, что, как я понял, вы спрашиваете:

int main(int argc, char const* argv[])
{
  boost::iostreams::filtering_istreambuf in;
  boost::regex regex("search");
  boost::iostreams::regex_filter rf(regex, "replace");
  in.push(rf);

  boost::iostreams::file_source file1(argv[1]);
  in.push(file1);

  boost::iostreams::file_source file2(argv[2]);
  boost::iostreams::copy(hamigaki::iostreams::concatenate(boost::ref(in), file2), std::cout);

  return 0;
}

Я просто использовал фильтр регулярных выражений вместо gzip для тестирования.

2) boost :: iostreams имеет фильтр регулярных выражений: http://www.boost.org/doc/libs/1_45_0/libs/iostreams/doc/classes/regex_filter.html

РЕДАКТИРОВАТЬ: Кажется, теперь у вас это работает.

person Pablo    schedule 22.02.2011
comment
Я нашел оба из них, но не смог заставить их работать так, как я хочу. Если вы можете показать, как решить мою проблему с ними, я приму это. - person chris; 22.02.2011
comment
Забыл сказать, что для boost :: ref требуется boost / bind.hpp - person Pablo; 22.02.2011

1) Недоступно в режиме ускорения

Конкатенация Хамигакиса звучит интересно, но я не мог понять, как используйте его для объединения двух boost :: iostreams :: цепочка s. В коде упоминается, что он предназначен для «объединения устройств», поэтому его нельзя использовать для цепочек. Пожалуйста, поправьте меня, если я ошибаюсь.

РЕДАКТИРОВАТЬ: обновил мой вопрос полным решением.

2a) поведение grep (фильтр):

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/grep.hpp>

boost::iostreams::filtering_istreambuf in;
boost::regex regex("^search")
boost::iostreams::grep_filter grep(regex);
in.push(grep);

2b) поведение sed (поиск / замена):

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/regex.hpp>

struct formatter {
    std::string operator()(const boost::match_results<const char*>& match)
    {
        return str(boost::format("%s | %s") % match[2] % match[1]);
    }
};
boost::iostreams::filtering_istreambuf in;
boost::regex regex("^([a-z]+) ([0-9]+)");
boost::iostreams::regex_filter sed(regex, formatter());
in.push(sed);
person chris    schedule 22.02.2011
comment
@bta: Нет, это не так. Ответ относится к моему собственному вопросу. - person chris; 22.02.2011