возврат значения из оболочки в программу C

У меня простой вопрос:

Я пишу программу на C со следующей структурой:

int qty_used;

qty_used = system("df -h | grep 'sda1' | awk 'BEGIN{print "Use%"} {percent+=$5;} END{print percent}'");

if (qty_used<fixed_limit)
   /* action 1 */
else
   /* action 2*/;

так что если это ситуация:

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       2.0T   30G  1.8T   2% /

Я хочу, чтобы qty_used загружался с целочисленным значением 2. Я никогда раньше не использовал awk и начал с этого многообещающего ответа: https://unix.stackexchange.com/questions/64815/how-to-print-процентиспользованиядискаиз-df-hl. Результат:

df -h | grep 'sda1' | awk 'BEGIN{print "Use%"} {percent+=$5;} END{print percent}'

звучало хорошо. Но если я попрошу [мне нужно было только целое число]:

df -h | grep 'sda1' | awk 'BEGIN{percent+=$5;} END{print percent}'

тогда выход равен нулю, а не 2 больше

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

Итак, вопрос: есть ли быстрый способ решить эту проблему, начиная с этих строк?

Спасибо тем, кто попытается помочь


person Antonino    schedule 02.03.2015    source источник
comment
Вы уверены, что идете об этом правильно? Если вам не нужны сложные структуры данных, вы можете просто использовать awk вместо C, а если вам действительно нужен C, разве нет библиотек, которые вы можете включить для доступа к примитивам UNIX, а не для вызова команд оболочки?   -  person Ed Morton    schedule 03.03.2015
comment
Да, @EdMorton, мне нужен C, потому что эта часть является частью более крупной программы на C, а не просто отдельным запросом. Что касается последней части вашего вопроса, я не настолько опытен в UNIX, чтобы понять, как вы могли бы создать ответ команды du, используя примитивы UNIX вместо вызова команд оболочки, для новичка, такого как я, было бы очень интересно знать. Спасибо за ваши добрые предложения!   -  person Antonino    schedule 03.03.2015
comment
Спросите в usenet по адресу comp.unix.programmer, и они смогут указать вам правильное направление для использования правильных примитивов. Это также может быть отправной точкой: cs.cf.ac.uk/ Dave/C/node20.html (я только что погуглил статистику файлов UNIX из программы C). Вы также можете найти stackoverflow.com/questions/1129499/ интересен.   -  person Ed Morton    schedule 03.03.2015
comment
Я посмотрю как можно скорее... вы очень любезны, спасибо, что нашли мне нужные рекомендации и хорошего дня!   -  person Antonino    schedule 03.03.2015


Ответы (3)


Вы должны понимать, что функция system() возвращает значение, связанное с кодом выхода команды, а не с выводом команды. Вы также должны понимать, что диапазон возможных кодов выхода довольно мал.

С учетом сказанного, если вам нужно поддерживать только целые значения от 0 до 100, вы должны иметь возможность завершить команду с помощью соответствующего кода. Это должно сделать это:

#include <sys/types.h>
#include <sys/wait.h>

/* ... */

    qty_used = WEXITSTATUS(
            system("exit `df -h | awk '/sda1/{percent+=$5;} END{print percent}'`"));

Обновление: удалено grep из конвейера команд согласно комментарию @EdMorton.

person John Bollinger    schedule 02.03.2015
comment
Вам не нужен grep, когда вы используете awk: df -h | awk '/sda1/{percent+=$5} END{print percent}'. - person Ed Morton; 03.03.2015
comment
спасибо @john, это как раз тот ответ, о котором я просил! что касается функции system(), мои слова были цитатой из абзаца возвращаемого значения в linux.die. net/man/3/system, где они также упоминают предложенный вами WEXITSTATUS. Еще раз спасибо за большую поддержку! - person Antonino; 03.03.2015
comment
@Антонино, рад быть полезным. Обратите внимание, однако, что хотя WEXITSTATUS() необходим, это не секретный соус. Суть в том, чтобы преобразовать вывод конвейера в код выхода, сделав его аргументом команды оболочки exit. - person John Bollinger; 03.03.2015

Один простой способ...

последняя функция (awk) перенаправляет вывод в файл (используя «> имя файла»)

затем откройте файл для чтения и извлеките нужную информацию.

person user3629249    schedule 02.03.2015
comment
спасибо @ user3629249, я читал об этом подходе в других ответах, но, если возможно [= если есть другой более быстрый способ решить эту проблему, начиная с моего черновика], я бы предпочел не открывать и работать с файлом только для одного числа. В любом случае ваша помощь очень ценится - person Antonino; 03.03.2015

Это увеличивает процент в блоке BEGIN...

$ df -h | grep 'sda1' | awk 'BEGIN{percent+=$5;} END{print percent}'
0

Пожалуйста, сравните (возможно, это и имелось в виду?)

$ df -h | grep 'sda1' | awk 'BEGIN{percent=0;} {percent+=$5;} END{print percent}'
2

Кроме того, система возвращает статус команды, а не ее вывод. Пожалуйста, рассмотрите возможность использования popen и чтения из потока.

Например, используя popen...

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

#define SIZE 2048

int get_percent_used (const char* devicename);

int main(int argc, char** argv) {
    int qty_used = get_percent_used("/dev/sda1");
    printf ("qty_used = %d percent\n", qty_used);
    return 0;
}

int get_percent_used (const char* devicename)
{
    char buffer[SIZE];
    char command[SIZE];
    FILE* pipe = 0;
    int percent = 0;

    sprintf (command, "df -h | grep '%s' | awk 'BEGIN{percent=0;} {percent+=$5;} END{print percent}'", devicename);

    if (!(pipe = popen(command, "r"))) {
        perror("open failed");
        return 1;
    }

    while (fgets(buffer, SIZE, pipe) != NULL) {
        percent += (int) strtol(buffer, NULL, 10);
    }
    pclose(pipe);

    return percent;
}
person codess    schedule 02.03.2015
comment
спасибо @codess, как я уже говорил, я читал о функции system() в ссылке, указанной в другом комментарии... ваша вторая строка - это именно то, что я пытался сделать... тогда мне нужно было это значение [т.е. 2] для загрузки в целое число C, как это сделал Джон... спасибо и вам за вашу поддержку! - person Antonino; 03.03.2015
comment
Спасибо @Антонино. Насколько я могу судить, WEXITSTATUS по-прежнему возвращает информацию только о статусе завершения процесса; поэтому я отредактировал свой ответ, чтобы добавить пример кода, если он вообще поможет. - person codess; 03.03.2015
comment
еще раз спасибо! поможет точно, мне и кто будет читать по той же проблеме - person Antonino; 03.03.2015