UNIX vs. C++ !

Ik heb al een tijdje zitten Googlen en vind nog steeds niet hoe ik een UNIX commando (deftig) kan uitvoeren via C++ (en opslaan in een variabele uiteraard). Wel heb ik ondekt, dat het beter is om de functie te gebruiken ipv het commando zelf. Bv: "getlogin()" ipv "id -un". Maar ik zou dan graag de functies weten voor elk commando, bestaat hier ergens een databank/tabel van ?

  • Bv. Wat is de functie voor “ls” (list directory contents) ?
  • Of hoe kan via C++ dit bereikt worden: “sudo periodic daily” ?

Iemand ?

Voor "ls" is geen functie, want dat is geen systemcall maar een losse utility.

Wil je een programma aanroepen en de output lezen (of er input heen sturen), dan zul je iets met pipes moeten doen. Het principe is hetzelfde als het gebruik van pipes op de commandline, alleen gebruik je nu filedescriptors om te communiceren.

Wellicht kan Creating Pipes in C je verder helpen.

Weet er ook niet echt veel van, maar kan je geen gebruik maken van shellscripts en die aanroepen (al weet ik helaas niet hoe) vanuit je C++ code?

Hoi,

Eerlijk gezegd (hoop niet dat dit lullig overkomt), weet je zelf wel waar je het precies overhebt?
Ik denk dat je eerst wat meer over programmeren moet leren. Je zult header files moeten includen (zoals in c)

dus bijv.

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

etc.

Basis systeemcommando’s zitten daarin (simpel gezegd). Wil je meer dingen doen dan kan dit niet met een taal zoals c of c++ zonder library’s in te linken. Uiteraard is het beter om de functie zelf te gebruiken.

Als je iets wilt ‘scripten’, zoals wat jij wil, kan je mischien beter denken om het in korn shell of python of perl te maken. Shell is wat eenvoudiger te leren. Maar c of c++ kost je wel wat tijd om het e.e.a te leren.

In ieder geval, veel succes.

[img:9028522025]http://images.amazon.com/images/P/0764568523.02._SCLZZZZZZZ_.jpg[/img:9028522025]

:?

Het is voor mij wel erg lang geleden dat ik dergelijke dingen deed vanuit C-programma's waarbij ik gebruik maakte van m.n. de Standaard C library (libc, -lc). In C++ moet het volgens mij op eenzelfde manier gaan. Omdat e.e.a. soms erg omslachtig was, heb ik me verdiept in het maken van C-shell scripts waarbij een aantal zaken toch wel vrij makkelijk gingen en goed parametriseerbaar waren.

Echter wat betreft je vraag moet je volgens mij, na bestudering van een aantal manual pages (beginnend met man execv), vrij ver kunnen komen. Je kan manual pages opvragen door in een Terminal window het commando: man execv te geven.

Wat ook een goede bron van informatie is, is via Google in de newsgroupen:
alt.comp.lang.c, alt.comp.lang.c++.help, comp.lang.c, comp.lang.c++
te zoeken, waarbij het snel vinden van antwoorden afhangt hoe goed je je vraag formuleert.

Succes ermee!

Met hulp van die pagina waarnaar ik verwees, heb ik een klein programmaatje in elkaar gehackt dat het principe wel aardig demonstreert denk ik: [code:1:85a5b36fe5]#include <sys/types.h> #include <unistd.h> #include <stdio.h>

int main()
{
int fd[2];
pid_t pid;
char buffer[80];

    pipe&#40;fd&#41;;

    if &#40;&#40;pid = fork&#40;&#41;&#41; == -1&#41;
    &#123;
            perror&#40;&quot;fork&quot;&#41;;
            exit&#40;1&#41;;
    &#125;

    if &#40;pid == 0&#41;
    &#123;
            /* Child process */
            close&#40;fd&#91;0&#93;&#41;;
            close&#40;1&#41;;
            dup&#40;fd&#91;1&#93;&#41;;
            execl&#40;&quot;/bin/date&quot;, NULL&#41;;
    &#125;
    else
    &#123;
            /* Parent process */
            close&#40;fd&#91;1&#93;&#41;;
            &#40;void&#41;read&#40;fd&#91;0&#93;, buffer, sizeof&#40;buffer&#41;&#41;;
            printf&#40;&quot;Parent got&#58; %sn&quot;, buffer&#41;;
    &#125;

    return&#40;0&#41;;

}[/code:1:85a5b36fe5]
Uitvoer:

[code:1:85a5b36fe5]$ cc demo.c -o demo
$ ./demo
Parent got: Wed Sep 14 08:56:29 CEST 2005[/code:1:85a5b36fe5]
Door de man-pages over hierboven gebruikte calls te lezen moet je er wel achter kunnen komen hoe één en ander werkt (zie bijvoorbeeld [i:85a5b36fe5]man fork[/i:85a5b36fe5], [i:85a5b36fe5]man pipe[/i:85a5b36fe5] en [i:85a5b36fe5]man dup[/i:85a5b36fe5]).

Ik heb er ook een gevonden: [code:1:c2da6c22a2]#include <iostream> #include <stdlib.h>

int main (int argc, char * const argv[])
{
char* command="id -un";
system(command);

return 0;

}
[/code:1:c2da6c22a2]
Maar nu ben ik nog opzoek hoe men een shell-resultaat opslaat in een variabele…
In AppleScript is het uiteraard gemakkelijk en gaat het alsvolgt:

[quote:c2da6c22a2]set theResult to do shell script “id -un”
display dialog theResult as string[/quote:c2da6c22a2]
Ik zou iets gelijkaardigs willen bereiken (zonder de dialoog maar het effect van het resultaat in een variabele te stoppen), maar dan met C++.

Kan dat ? Ik veronderstel van wel ? :?

Ik denk dat ik er wel uitkom... En, Alef, het programmeren lukt erg goed in C++, het is gewoon de eerste maal dat ik dingen via de shell wil gaan doen... :wink:

[quote:3c037af410="BIT"]Maar nu ben ik nog opzoek hoe men een shell-resultaat opslaat in een variabele... Ik zou iets gelijkaardigs willen bereiken (zonder de dialoog maar het effect van het resultaat in een variabele te stoppen), maar dan met C++.[/quote:3c037af410] Zie mijn voorbeeld hierboven. Het programma forkt zichzelf waardoor je als het ware twee processen krijgt. Het ene process gaat je commando uitvoeren (date in dit geval), het andere gaat de uitvoer daarvan inlezen en opslaan in een string. Om dit te bewerkstelligen moeten ze hun stdin en stdout (standaard in- en uitvoer) aan elkaar knopen, middels pipes.

Volgens mij is dit wat jij zoekt, al ziet het er wat omslachtig uit. Jouw system aanroep doet intern min of meer hetzelfde (zie man system). Het forkt zichzelf ook naar twee processen, waarbij het ene proces je shell-commando uitvoert en het andere proces wacht tot dit klaar is. Er wordt alleen geen uitvoer opgeslagen of geredirect.

Hiervoor moet je zelf dus wat moeite doen.

Je had in plaats van die pipe ook een gezamelijke buffer kunnen gebruiken ;) Nadeel is dan wel dat je van tevoren dient te weten hoe groot de buffer is.

Ja, maar stel nu dat je dit wil opslaan in een variabele: [code:1:aab598312a]$ ifconfig -lu[/code:1:aab598312a] Zou dat gaan ? :P

[quote:aa231e59a6="Reflex"]Je had in plaats van die pipe ook een gezamelijke buffer kunnen gebruiken ;) Nadeel is dan wel dat je van tevoren dient te weten hoe groot de buffer is.[/quote:aa231e59a6] Misschien mis ik wat, maar hoe krijg je dan alsnog de uitvoer van het programma dat je aanroept in die buffer?

En nu voor je [i:aa231e59a6]ifconfig[/i:aa231e59a6] probleem, uitgespeld en al… :wink:

[code:1:aa231e59a6]#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
int fd[2];
pid_t pid;

    pipe&#40;fd&#41;; 

    if &#40;&#40;pid = fork&#40;&#41;&#41; == -1&#41; 
    &#123; 
            perror&#40;&quot;fork&quot;&#41;; 
            return 1; 
    &#125; 

    if &#40;pid == 0&#41; 
    &#123; 
            /* Child process */ 
            close&#40;fd&#91;0&#93;&#41;; 
            close&#40;1&#41;; 
            dup&#40;fd&#91;1&#93;&#41;; 
            execl&#40;&quot;/sbin/ifconfig&quot;, &quot;ifconfig&quot;, &quot;-lu&quot;, NULL&#41;; 
    &#125; 
    else 
    &#123; 
            /* Parent process */ 
            char ch;

            close&#40;fd&#91;1&#93;&#41;; 
            while &#40;read&#40;fd&#91;0&#93;, &amp;ch, 1&#41; &gt; 0&#41;
            &#123;
                printf&#40;&quot;%c&quot;, ch&#41;;
            &#125;
    &#125; 

    return 0; 

}[/code:1:aa231e59a6]
Voorbeeld aanroep:

[code:1:aa231e59a6]$ cc demo.c -o demo && ./demo
lo0 en0 en1 fw0[/code:1:aa231e59a6]
Niet zo heel moeilijk toch?

Aaah zo doe je dat. Ongeloofelijk bedankt. Ik had misschien beter de man-pagina van execl() eens bekeken, dan had ik het niet moeten vragen :P ...

@ Maccessory ugh, natuurlijk :) my bad, ik dacht even dat er enkel gegevens tussen de twee processen uitgewisseld hoefde te worden, maar je moet natuurlijk de console uitlezen. My bad, verkeerd gelezen :)

No problem, we're here to help... :D

Ik weet dat dit topic al oud is, maar ik heb toch nog iets gevonden op een of ander engels forum (niet dat ik er nog steeds mee bezig ben hoor :wink: ):

De code doet eigenlijk gewoon dit: ls -l /var/log.

[code:1:883b97a437]#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main (int argc, char * const argv[])
{
int kidstatus, deadpid;
pid_t kidpid = fork();

if &#40;kidpid == -1&#41;
&#123;
	std&#58;&#58;cerr &lt;&lt; &quot;fork errorn&quot;;
	return 1;
&#125;
if &#40;kidpid == 0&#41;
&#123;
	// okay, we're the child process. Let's transfer control
	// to the ls program. &quot;ls&quot; in both of the spots in the list
	// is not a mistake! Only the second argument on are argv.
	// note the NULL at the end of the list, you need that.
	#if 0
		// this version uses the shell.
		int rv = execlp&#40;&quot;/bin/sh&quot;, &quot;/bin/sh&quot;, &quot;-c&quot;, &quot;ls -l /var/log&quot;, NULL&#41;;
	#else
		// this version runs /bin/ls directly.
		int rv = execlp&#40;&quot;/bin/ls&quot;, &quot;/bin/ls&quot;, &quot;-l&quot;, &quot;/var/log/&quot;, NULL&#41;;
	#endif
	// if the execlp is successful we never get here&#58;
	if &#40;rv == -1&#41;
	&#123;
		std&#58;&#58;cerr &lt;&lt; &quot;execlp errorn&quot;;
		return 99;
	&#125;
	return 0;
&#125;
// we only get here if we're the parent process.
deadpid = waitpid&#40;kidpid, &amp;kidstatus, 0&#41;;
if &#40;deadpid == -1&#41;
&#123;
	std&#58;&#58;cerr &lt;&lt; &quot;waitpid errorn&quot;;
	return 1;
&#125;
std&#58;&#58;cout &lt;&lt; &quot;child result code&#58; &quot; &lt;&lt; WEXITSTATUS&#40;kidstatus&#41; &lt;&lt; &quot;n&quot;;
return 0;

}[/code:1:883b97a437]
Is er een verschil tussen dit en het voorbeeld van jou, Maccessory ?

:innocent:

Het lijkt erop, maar het redirect geen in- en uitvoer. Dus de uitvoer van het ls commando verschijnt rechtstreeks op de console (je Terminal venster) en wordt niet eerst afgevangen en opgeslagen door het programma zelf.

Ter info, waarom ze het op deze manier doen (het uitvoeren van een ls commando door eerst een proces te forken) is dat zodra je via execlp() iets uitvoert, je eigen proces weggeschoten wordt. Na de aanroep van ls is je eigen proces er dus niet meer om naar terug te keren, dus je kunt nadien niets doen met de uitvoer of de exit waarde van het ls commando.

Door eerst te forken, het kind process de execlp() uit te laten voeren en het parent process te laten wachten tot het kind process klaar is (middels waitpid()), blijf jezelf “in de lucht” en kun je na afloop zelf verder. Je ziet dat 'ie hier dan laat zien of er een fout opgetreden was (“waitpid error”) of anders wat de return value van het ls commando was (WEXITSTATUS).

Niet erg C++ allemaal (wel erg C), en voor C++ zijn er toch allemaal STL-bibliotheken (std) die transparant fileoperaties doen, en nette excepties "werpen", e.d. Dan is het netjes opject-georienteerd en werkt de code op ieder OS, in principe. Dit is allemaal vrij Unix-ig (niet daar iets mis mee is :wink: , ben zelf een grote fan), en niet echt in geest van C++. Zie is, os, ios etc. zie bv.

http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#1

http://www.cplusplus.com/ref/cstdio/

etc.

HB