1 Kasım 2016 Salı

popen ve _popen metodları

Giriş
Şu satır dahil edilir.
#include <stdio.h>
popen metodu
Çalıştırılan uygulamanın ya stdout veya stdin akımını alır. sterr akımını kullanmaz!

İmzası
İmzası şöyledir.
FILE *popen(const char *command, const char *type);
type alanına "r" veya "w" karakteri gelir. Açıklaması şöyle
The type argument is a pointer to a null-terminated string which must contain either the letter 'r' for reading or the letter 'w' for writing.
POSIX dokümanında da benzer yazı mevcut. Açıklaması şöyle
The character 'b' shall have no effect, but is allowed for ISO C standard conformance.
Okumak İçin
Şöyle yaparız.
FILE* pipe = popen("...", "r");
Şu kod hatalı. Çünkü okuma akımı zaten binary açılır.
FILE* pipe = popen("...", "rb");
Hata Yakalama
Eğer olmayan bir komut çalıştırılmaya çalışılırsa FILE* null dönmüyor. Bu durumda ne yapmak lazım bilmiyorum.

popen kabuğu kullanır
popen() çağrısı std::system() çağrısına benzer şekilde alt tarafta fork() ile yeni bir child process oluşturuluyor ve child içinde yine aynı şekilde

execl(_PATH_BSHELL, "sh", "-c", program, NULL);

çağırılıyor. Ancak arada fark olarak child process yaratılmadan önce bir pipe oluşturuluyor.

int pdes[2];
pipe(pdes);

popen "r" ile çağrılmışsa child process çalışmaya başladıktan sonra yaratılmış olan pipe'ın okuma ucu STDOUT_FILENO ile yer değiştiriyor.

close(pdes[0]);//Pipe'ın okuma ucunu kapat
(void)dup2(pdes[1], STDOUT_FILENO);//Pipe'ın yazma ucu stdout ile aynı olsun
(void)close(pdes[1]);//Pipe'ın yazma ucunu da kapat


Bu işlemin ardından çağırılan execl() ile çalıştırılan shell output stream olarak yaratılan pipe'a yazdığı için parent process'te child'ın çıktısını okuyabiliyor.

Burada dikkat edilmesi gereken nokta çalıştırılan uygulamanın ya stdin veya stdout akımının kullanılması, stderr akımı kullanılmıyor. Hepsini birden kullanmak için buraya bakabilirsiniz.

Örnekler
Kendi script'imi çalıştırmak için şöyle yaparız.
#include <iostream>
#include <stdio.h>

using namespace std;

int main() 
{

    FILE *in;
    char buff[512];

    if(!(in = popen("my_script_from_command_line", "r"))){
        return 1;
    }

    while(fgets(buff, sizeof(buff), in)!=NULL){
          cout << buff; // here you have each line 
                        // of the output of your script in buff
    }
    pclose(in);

    return 0;
}
ls uygulamasını çalıştırmak için şöyle yaparız.

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

int main() {
    FILE *process;
    char buff[1024];

    process = popen("ls -l", "r");

    if (process != NULL) {
        while (!feof(process)) {
            fgets(buff, sizeof(buff), process);
            printf("%s", buff);
        }

        pclose(process);
    }

    return 0;
}
bash komutu çalıştırmak için şöyle yaparız.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main ()
{
    // get PATH using pipe
    FILE* pip = popen("exec bash -c 'echo $PATH'", "r");
    if (!pip)
    {
        printf("can not open pipe!");
        return 1;
    }

    char lineversion[600];
    memset (lineversion, 0, sizeof(lineversion));
    if (!fgets(lineversion, sizeof(lineversion), pip))
    {
        printf("fgets error!");
        return 1;
    }

    std::cout << lineversion << std::endl;

    // get PATH using getenv
    char* pPath = getenv ("PATH");
    std::cout << pPath << std::endl;
}
_popen ve _pclose
Bu metod Windows'taki C kütüphanesinde bulunur. popen() ile hemen hemen aynıdır. Şöyle yaparız.
const std::string command = ...;
FILE* output = _popen(command.c_str(), "r");
...
_pclose(output);
pclose metodu
İşlem bitince FILE* pclose() ile kapatılmalıdır.





Hiç yorum yok:

Yorum Gönder