Функциональность встроенных консольных инструментов в приложении - PullRequest
0 голосов
/ 23 октября 2009

В настоящее время я разрабатываю приложение, которое требует предварительной обработки файла перед чтением данных.

Выполнение этого извне было невозможным, поэтому я придумал форк & execve «cut options filename | sort | uniq -c» и т. Д. И выполняю его так.

Однако я подумал, что, возможно, уже есть другая возможность повторно использовать все эти древние и хорошие рабочие инструменты непосредственно в моем коде и не вызывать их через оболочку.

В настоящее время я смотрю на busybox, чтобы увидеть, есть ли простой способ статически связать и программно вызвать эти утилиты, но пока не повезло.

Ответы [ 8 ]

4 голосов
/ 19 ноября 2009

Аркайц, ответ нет, из-за того, как вы сформулировали вопрос.

Вы просите "еще один вариант повторно использовать все эти древние и хорошие рабочие инструменты прямо в моем коде и не вызывать их через оболочку"

Проблема в том, что правильный и общепринятый способ повторного использования всех этих древних и хороших рабочих инструментов - это именно то, о чем вы говорите, что вы хотите избежать - вызывая их через оболочку (или, по крайней мере, запуская их как ребенка). например, через popen) - и определенно не рекомендуется пытаться включать, копировать или дублировать эти инструменты в ваш код.

Модель манипулирования данными в UNIX (и Linux) надежна и проверена - зачем вам этого избегать?

3 голосов
/ 19 ноября 2009

«Древние» инструменты были созданы для использования оболочкой, а не для того, чтобы встраивать их в исполняемый файл. Однако существуют более свежие инструменты, которые делают многое из того, что вы показали в препроцессоре командной строки: iostreams с экстракторами (для замены cut), std::sort и std::unique для замены соответствующих программ ...

struct S { string col1, col3; 
   bool operator<( const S& s ) { return col1 < s.col1; }
};
vector<S> v;
while( cin ) {
  S s;
  string dummy;
  cin >> s.col1 >> dummy >> col3 >> dummy;
  v.push_back( s );
}
sort(v.begin(), v.end(), S::smaller );
unique( v.begin(), v.end() );

Не слишком сложно, я думаю.

2 голосов
/ 24 октября 2009

Попробуйте popen ().

char buffer [ BUFFER_SIZE ];
FILE * f = popen( "cut options filename | sort | uniq -c", "r" );
while( /*NOT*/! feof(f) )
  fgets( buffer, BUFFER_SIZE, f );
pclose( f );

Ссылка: Как выполнить команду и получить вывод команды в C ++, используя POSIX?

1 голос
/ 20 ноября 2009

Хороший способ сделать это:

  • Создать 2 трубы
  • Форк новый процесс
  • Заменить stdin и stdout для дочернего процесса на трубы с использованием dup2 функция
  • exec команда, которую вы хотите
  • Запись и чтение из родительского процесса с использованием каналов
1 голос
/ 20 ноября 2009

Просто напишите еще один полезный «древний и добрый» инструмент;), прочитайте все данные из стандартного ввода и верните их в стандартный вывод.

cat *.txt | grep 'blabla' | sort | my_new_tool | tee -o res_file

1 голос
/ 23 октября 2009

Вы должны сделать это через оболочку, но проще использовать «системный» вызов.

while(something) {
           int ret = system("foo");

           if (WIFSIGNALED(ret) &&
               (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT))
                   break;
       }
0 голосов
/ 17 ноября 2009

Если вы не хотите вызывать внешние команды (exec, popen, system и т. Д.), Но не хотите изменять источник этих утилит и компилировать их в свой код (сравнительно легко, просто измените «main» на « main_cut 'и т. д.), тогда единственная оставшаяся опция, которую я вижу, это встраивать утилиты в ваш код и извлекать их во время выполнения или динамически создавать систему хранения файлов, указывая на данные внутри вашего кода (например, используя образ дискеты или CD и записывая модуль FUSE, который берет данные образа диска с адреса оперативной памяти). Все это кажется большой работой, чтобы сделать ее похожей на аккуратно упакованную утилиту.

Лично, если бы мне действительно пришлось это сделать, я бы получил источник всех этих утилит и скомпилировал их как внешние вызовы. Конечно, у вас больше не будет легко доступных каналов, вам придется либо использовать временные файлы для предварительной обработки, либо что-то более сложное, включая сопрограммы. Или, может быть, розетки. Много работы и грязи, что бы вы ни делали!

0 голосов
/ 23 октября 2009

busybox также был моей первой мыслью, хотя вы также можете подумать о внедрении скриптового движка, такого как Python, и выполнении подобных манипуляций в скриптах Python.

Я бы определенно не пытался исключить такую ​​функциональность из инструментов командной строки GNU, поскольку они значительно выросли с первых дней существования UNIX и привели к огромному количеству вариантов.

Если код busybox кажется слишком сложным для адаптации, то следующее место, которое я бы посмотрел, было бы Исходный код Minix . Посмотрите в разделе «Предыдущие версии» и выберите один из версий 1 или 2 «Миниксы», потому что они написаны как обучающий код, поэтому они, как правило, становятся все яснее и проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...