2015-09-01 1 views
0

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

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

int main() 
{ 

    return print_osinfo(); 
} 

int print_osinfo() 
{ 
    FILE *fp; 
    extern FILE* popen(); 
    char buffer[128]; 
    int index = 0; 

    memset(buffer,0,sizeof(buffer)); 
    fp = popen("/etc/centos-release", "r"); 
    if(!fp) 
    { 
     pclose(fp); 
     fp = popen("/etc/redhat-release", "r"); 
     if(!fp) 
     { 
      pclose(fp); 
      return 1; 
     } 
    } 
    while(fgets(buffer, sizeof(buffer), fp)!= NULL) 
    { 
     printf("%s\n",buffer); 
    } 
    pclose(fp); 
    return 0; 
} 

Если я запустил вышеуказанный код на Ubuntu 14.04, то получаю следующее сообщение об ошибке.

sh: 1: /etc/centos-release: not found 

Я не понимаю, почему он не пытается открыть redhat-release, а затем вернуть -1. Кроме того, существует ли способ предотвратить отображение вышеуказанной ошибки на экране?

+3

Возможно, перенаправляя 'stderr', как этот' popen ("/ etc/centos-release 2>/dev/null", "r") '? Или возможно 'popen ("/etc/centos-release 2> & 1 "," r ");' 'stderr' перенаправляется на' stdout' – Cyclonecode

+4

Ни/etc/centos-release, ни/etc/redhat-release не являются исполняемыми файлами, поэтому вам не нужно использовать popen/pclose для их чтения - просто используйте fopen/fclose. Используйте popen/pclose для запуска чего-то вроде «uname -a», который испускает некоторую текстовую информацию о текущей системе. – sjnarv

+2

Ошибки не записываются в stdout, как указывает заголовок вашего вопроса. Они записываются в stderr. –

ответ

5

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

Если вы действительно хотите использовать popen, он принимает команду оболочки, поскольку это первый аргумент, а не имя файла. Вместо этого попробуйте popen("cat /etc/centos-release","r");.

Теперь вы можете быть немного смущены, потому что обе эти функции возвращают указатель FILE. fopen возвращает указатель на файл, который вы передали в качестве аргумента. popen, однако, возвращает трубу, указывающую на вывод команды, которую вы ей передали, которая видит C как указатель FILE. Это связано с тем, что в C все i/o - это доступ к файлам; Единственное соединение C с внешним миром - через файлы. Итак, чтобы передать вывод какой-либо команды оболочки, popen создает то, что C видит как FILE в памяти, содержащий вывод команды оболочки. Так как довольно абсурдно запускать целую другую программу (команду оболочки) только для того, чтобы сделать то, что делает fopen, отлично имеет смысл просто использовать fopen для чтения из файлов, которые уже существуют на диске.

+3

Почему не просто 'fp = fopen ("/etc/centos-release "," r ")' (а затем 'fclose (fp)')? Нет очевидной причины использовать оболочку и «кошку», когда вы просто пытаетесь прочитать файл. И 'fopen()' не записывает в 'stderr', что устраняет проблему с сообщением об ошибке. –

+1

Вопрос касался использования 'popen()'. Я полностью согласен с тем, что 'fopen()' лучший выбор здесь, но я хотел объяснить, почему это не сработало, а не просто другим способом сделать это. –

+1

Да, но вопрос был также в том, чтобы выполнить файл, который не является исполняемым. Вы можете разумно предложить лучшее решение ('fopen()', 'fclose()'), а затем прокомментировать «если вы должны использовать' popen() 'then ...". Не указывая на большинство ошибок их способов, не так полезно, как это делается. Также заголовок посвящен остановке ошибок, возникающих при стандартной ошибке; ваше решение не сделало этого, когда файл «/ etc/redhat-release»; 'cat/etc/centos-release' будет генерировать ошибку. –

Смежные вопросы