implementação de vários pipes em c
<p>eu estou tentando implementar vários pipes no meu shell em c. eu encontrei um tutorial sobre este <a href="http://www.cs.loyola.edu/~jglenn/702/s2005/examples/dup2.html">site</a> ea função que fiz baseia-se neste exemplo. aqui está a função</p><pre><code>void executepipes(cmdline* command, char* userinput) { int numpipes = 2 * countpipes(userinput); int status; int i = 0, j = 0; int pipefds[numpipes]; for(i = 0; i &lt; (numpipes); i += 2) pipe(pipefds + i); while(command != null) { if(fork() == 0){ if(j != 0){ dup2(pipefds[j - 2], 0); } if(command-&gt;next != null){ dup2(pipefds[j + 1], 1); } for(i = 0; i &lt; (numpipes); i++){ close(pipefds[i]); } if( execvp(*command-&gt;arguments, command-&gt;arguments) &lt; 0 ){ perror(*command-&gt;arguments); exit(exit\_failure); } } else{ if(command != null) command = command-&gt;next; j += 2; for(i = 0; i &lt; (numpipes ); i++){ close(pipefds[i]); } while(waitpid(0,0,0) &lt; 0); } } } </code></pre><p>depois de executá-lo e digitar um comando como, por exemplo, <code>ls | grep bin</code>, o shell simplesmente fica parado e não produz nenhum resultado. eu me certifiquei de fechar todos os canos. mas apenas fica pendurado lá. eu pensei que era o <code>waitpid</code> que era o problema. eu removi o <code>waitpid</code> e depois de executar não recebo resultados. o que eu fiz errado? obrigado.</p><p>código adicionado:</p><pre><code>void runpipedcommands(cmdline* command, char* userinput) { int numpipes = countpipes(userinput); int status; int i = 0, j = 0; pid\_t pid; int pipefds[2*numpipes]; for(i = 0; i &lt; 2*(numpipes); i++){ if(pipe(pipefds + i*2) &lt; 0) { perror("pipe"); exit(exit\_failure); } } while(command) { pid = fork(); if(pid == 0) { //if not first command if(j != 0){ if(dup2(pipefds[(j-1) * 2], 0) &lt; 0){ perror(" dup2");///j-2 0 j+1 1 exit(exit\_failure); //printf("j != 0 dup(pipefd[%d], 0])\n", j-2); } //if not last command if(command-&gt;next){ if(dup2(pipefds[j * 2 + 1], 1) &lt; 0){ perror("dup2"); exit(exit\_failure); } } for(i = 0; i &lt; 2*numpipes; i++){ close(pipefds[i]); } if( execvp(*command-&gt;arguments, command-&gt;arguments) &lt; 0 ){ perror(*command-&gt;arguments); exit(exit\_failure); } } else if(pid &lt; 0){ perror("error"); exit(exit\_failure); } command = command-&gt;next; j++; } for(i = 0; i &lt; 2 * numpipes; i++){ close(pipefds[i]); puts("closed pipe in parent"); } while(waitpid(0,0,0) &lt;= 0); } } </code></pre>
<p>eu acredito que a questão aqui é que você está esperando e fechando dentro do mesmo ciclo que está criando crianças. na primeira iteração, o filho executará (o que destruirá o programa filho, sobrescrevendo-o com seu primeiro comando) e, em seguida, o pai fechará todos os descritores de arquivo e aguardará que o filho termine antes de iterar para criar o próximo filho . nesse ponto, uma vez que o pai fechou todos os seus canais, qualquer outro filho não terá nada para escrever ou ler. como você não está verificando o sucesso de suas chamadas dup2, isso não será percebido.</p><p>se você quiser manter a mesma estrutura de loop, será necessário certificar-se de que o pai apenas feche os descritores de arquivo que já foram usados, mas deixe os que não foram usados ​​sozinhos. então, depois que todas as crianças tiverem sido criadas, seus pais podem esperar.</p><p><strong>edit</strong>: eu misturei o pai/filho na minha resposta, mas o raciocínio ainda é válido: o processo que vai para o fork novamente fecha todas as suas cópias dos pipes, então qualquer processo após o primeiro fork não terá descritores de arquivo válidos para ler/escrever.</p><p>pseudo código, usando uma matriz de pipes criada antecipadamente:</p><pre><code>/* parent creates all needed pipes at the start */ for( i = 0; i &lt; num-pipes; i++ ){ if( pipe(pipefds + i*2) &lt; 0 ){ perror and exit } } commandc = 0 while( command ){ pid = fork() if( pid == 0 ){ /* child gets input from the previous command, if it's not the first command */ if( not first command ){ if( dup2(pipefds[(commandc-1)*2], 0) &lt; ){ perror and exit } } /* child outputs to next command, if it's not the last command */ if( not last command ){ if( dup2(pipefds[commandc*2+1], 1) &lt; 0 ){ perror and exit } } close all pipe-fds execvp perror and exit } else if( pid &lt; 0 ){ perror and exit } cmd = cmd-&gt;next commandc++ } /* parent closes all of its copies at the end */ for( i = 0; i &lt; 2 * num-pipes; i++ ){ close( pipefds[i] ); } </code></pre><p>nesse código, o processo pai original cria um filho para cada comando e, portanto, sobrevive a toda a provação. as crianças verificam se devem receber sua entrada do comando anterior e se devem enviar sua saída para o próximo comando. em seguida, eles fecham todas as suas cópias dos descritores de arquivo de pipe e, em seguida, exec. o pai não faz nada além de bifurcar até que seja criado um filho para cada comando. em seguida, fecha todas as cópias dos descritores e pode esperar.</p><p>criar todos os canais de que você precisa primeiro e, em seguida, gerenciá-los no loop, é complicado e requer alguma aritmética de matriz. o objetivo, porém, é assim:</p><pre><code>cmd0 cmd1 cmd2 cmd3 cmd4 pipe0 pipe1 pipe2 pipe3 [0,1] [2,3] [4,5] [6,7] </code></pre><p>percebendo que, a qualquer momento, você só precisa de dois conjuntos de tubos (o pipe para o comando anterior e o pipe para o próximo comando) irá simplificar seu código e torná-lo um pouco mais robusto. ephemient dá pseudo-código para este <a href="https://stackoverflow.com/questions/916900/having-trouble-with-fork-pipe-dup2-and-exec-in-c/">aqui</a> . seu código é mais limpo, porque o pai e o filho não precisam fazer um loop desnecessário para fechar os descritores de arquivo desnecessários e porque o pai pode fechar facilmente suas cópias dos descritores de arquivo imediatamente após a bifurcação.</p><p>como uma nota lateral: você deve sempre verificar os valores de retorno de pipe, dup2, fork e exec.</p><p><strong> edit 2 </strong>: typo no pseudocódigo. op: num-pipes seria o número de pipes. por exemplo, &quot;ls | grep foo | sort -r&quot; teria 2 canais.</p>
oi andrei! o usethis::use\_pipe() (assim como os use\_package() ) deve ser usado no console, no contexto de um pacote. caso você queira guardar o código (para consulta posterior) recomendo deixar comentado.

a mensagem de erro diz que o pipe não foi encontrado, ou seja, ele não está carregado. a mensa… <p>vamos primeiro ver o que acontece se um programa for iniciado a partir de um shell interativo (conectado a um terminal) sem <code>&amp;</code> (e sem nenhum redirecionamento). então, vamos supor que você acabou de digitar <code>foo</code>:</p><ul> <li>o processo executando <code>foo</code> é criado.</li> <li>o processo herda stdin, stdout e stderr do shell. portanto, também está conectado ao mesmo terminal.</li> <li>se o shell receber um <code>sighup</code>, ele também envia um <code>sighup</code> para o processo (o que normalmente causa o término do processo).</li> <li>caso contrário, o shell aguarda (está bloqueado) até o processo terminar.</li> </ul><p>agora, vejamos o que acontece se você colocar o processo em segundo plano, ou seja, digite <code>foo &amp;</code>:</p><ul> <li>o processo executando <code>foo</code> é criado.</li> <li>o processo herda stdout/stderr do shell (portanto, ele ainda grava no terminal).</li> <li>o processo em princípio também herda stdin, mas assim que tenta ler a partir de stdin, ele é interrompido.</li> <li>ele é colocado na lista de trabalhos em segundo plano que a shell gerencia, o que significa especialmente: <ul> <li>ele está listado com <code>jobs</code> e pode ser acessado usando <code>%n</code> (onde <code>n</code> é o número do trabalho).</li> <li>ele pode ser transformado em um trabalho em primeiro plano usando <code>fg</code>, caso em que continua como se você não tivesse usado <code>&amp;</code> (e se foi interrompido devido à tentativa de leitura da entrada padrão, agora pode prosseguir com a leitura do terminal).</li> <li>se o shell recebeu um <code>sighup</code>, ele também envia um <code>sighup</code> para o processo. dependendo do shell e possivelmente das opções definidas para o shell, ao finalizar o shell, ele também enviará um <code>sighup</code> para o processo.</li> </ul> </li> </ul><p>agora <code>disown</code> remove o trabalho da lista de trabalhos do shell, para que todos os subpontos acima não se apliquem mais (incluindo o processo que está sendo enviado um <code>sighup</code> pelo shell). no entanto, observe que <em> ainda </em> está conectado ao terminal, portanto, se o terminal for destruído (o que pode acontecer se for um pty, como os criados por <code>xterm</code> ou <code>ssh</code>, e o programa de controle é finalizado, fechando o xterm ou finalizando a <a href="http://en.wikipedia.org/wiki/secure\_shell"> ssh </a> conexão), o programa falhará assim que tentar ler da entrada padrão ou gravar na saída padrão.</p><p>o que <code>nohup</code> faz, por outro lado, é separar efetivamente o processo do terminal:</p><ul> <li>ele fecha a entrada padrão (o programa <em> não </em> consegue ler qualquer entrada, mesmo que seja executada em primeiro plano. não é interrompido, mas será receba um código de erro ou <code>eof</code>).</li> <li>ele redireciona a saída padrão e o erro padrão para o arquivo <code>nohup.out</code>, para que o programa não falhe ao gravar na saída padrão se o terminal falhar, portanto, o que o processo gravar não será perdido.</li> <li>impede que o processo receba um <code>sighup</code> (portanto, o nome).</li> </ul><p>observe que <code>nohup</code> <em> não remove </em> o processo do controle de tarefas do shell e também não o coloca em segundo plano (mas desde que um primeiro plano <code>nohup</code> trabalho é mais ou menos inútil, você geralmente o coloca em segundo plano usando <code>&amp;</code>). por exemplo, diferentemente de <code>disown</code>, o shell ainda informa quando o trabalho nohup foi concluído (a menos que o shell seja encerrado antes, é claro).</p><p>então, para resumir:</p><ul> <li><code>&amp;</code> coloca o trabalho em segundo plano, ou seja, impede a tentativa de ler as entradas e faz com que o shell não espere sua conclusão.</li> <li><code>disown</code> remove o processo do controle de trabalho do shell, mas ainda o deixa conectado ao terminal. um dos resultados é que o shell não enviará um <code>sighup</code>. obviamente, ele só pode ser aplicado a trabalhos em segundo plano, porque você não pode inseri-lo quando um trabalho em primeiro plano está em execução.</li> <li><code>nohup</code> desconecta o processo do terminal, redireciona sua saída para <code>nohup.out</code> e o protege de <code>sighup</code>. um dos efeitos (o de nomeação) é que o processo não receberá nenhum <code>sighup</code> enviado. é completamente independente do controle do trabalho e pode, em princípio, ser usado também para trabalhos em primeiro plano (embora isso não seja muito útil).</li> </ul> <p>o comando <code>id -u</code> imprime o seu "id de usuário numérico" (curto: uid); como você já percebeu, é o mesmo que soletrar seu nome de usuário por completo na linha de comando <code>chown</code>. de fato, as seguintes invocações de comandos devem ter o mesmo efeito:</p><pre><code>sudo chown `id -u` /data/db sudo chown $user /data/db </code></pre><p>a razão pela qual ele não funcionou como esperado provavelmente tem a ver com as aspas: elas têm que ser <em> backquotes </em> (ascii char 0x60), enquanto a mensagem de erro <code>chown</code> sugere que você usou o single aspas (ascii char 0x27).</p><p>você pode encontrar uma explicação muito completa sobre o shell do unix, citando <a href="http://www.mpi-inf.mpg.de/~uwe/lehre/unixffb/quoting-guide.html#sect:shell-quot">aqui</a> .</p> fala pedro, beleza?cara, pelo que entendi você criou duas funções main, uma dentro da outra.sugiro que você faça o seguinte:[code=csharp]#include <stdio.h>#include <math.h>int main... <p>adicione o seguinte a ~/.bashrc</p><pre><code># avoid duplicates histcontrol=ignoredups:erasedups # when the shell exits, append to the history file instead of overwriting it shopt -s histappend # after each command, append to the history file and reread it prompt\_command="${prompt\_command:+$prompt\_command$'\n'}history -a; history -c; history -r" </code></pre> <p>adicione esta linha ao seu .vimrc:</p><pre><code>command r !./% </code></pre><p>e então você pode simplesmente digitar ": r" enquanto no vim para executar o script ( <a href="http://www.calebmadrigal.com/vim-run-current-file/">vim-run-current-file</a> )</p> <p>o <code>while</code> está checando se o valor é null. enquanto não for null, continua infinitamente.</p>
<p>o enter não é null. se quiser checar uma linha vazia, faça algo como <code>while(!s.isempty())</code></p> <p>em fluxos que suportam leitura e gravação, você tem duas posições, uma para leitura (por exemplo, "get" denotada por "g") e outra para gravação (ou seja, "put" denotada por "p").</p><p>e é por isso que você tem um <code>seekp</code> (herdado de <code>basic\_ostream</code>) e um <code>seekg</code> (herdado de <code>basic\_istream</code>).</p><p>nota: a linguagem c tem - em contraste com c++ - apenas uma dessas funções <code>fseek</code> para ambos os ponteiros; é necessário reposicionar o ponteiro quando se muda de leitura para escrita e vice-versa (por exemplo, <a href="https://stackoverflow.com/a/46152654/2630032">this</a> answer). para evitar isso, o c++ oferece funções separadas para leitura e gravação, respectivamente.</p> <p>uma maneira de obter a localização binária do processo é usar <code>lsof</code> e <code>grep</code> para o primeiro segmento <code>txt</code>. por exemplo, no shell para ver qual binário é o shell, use o pid do shell no lugar de <code>$$</code>.</p><pre><code>$ lsof -p $$ | grep txt bash 78228 blair txt reg 14,2 1244928 6568359 /bin/bash bash 78228 blair txt reg 14,2 1059792 23699809 /usr/lib/dyld bash 78228 blair txt reg 14,2 136368128 81751398 /private/var/db/dyld/dyld\_shared\_cache\_i386 </code></pre><p>você pode ver que o shell está usando <code>/bin/bash</code>.</p><p>essa técnica funciona se o processo foi iniciado usando um caminho absoluto ou relativo. por exemplo, entrar em um shell e executar</p><pre><code>$ sleep 1234567 </code></pre><p>e usar <code>ps</code> em outro shell mostra apenas como foi lançado:</p><pre><code>$ ps auxww|grep '[s]leep' blair 79462 0.0 0.0 600908 744 s011 s+ 11:17pm 0:00.00 sleep 1234567 </code></pre><p>usando <code>lsof</code> mostra qual binário ele executou:</p><pre><code>$ lsof -p 79462 | awk '$4 == "txt" { print $9 }' /opt/local-development/bin/gsleep </code></pre><p>eu tenho macports coreutils + with\_default\_names instalado, o que explica que eu peguei <code>gsleep</code> e não <code>/bin/sleep</code>.</p> #include #include int main(){int contpos = 0;int contneg = 0;int num;while (num != 0){printf ("digite o número pretendido:");scanf ("%d", num);if (num >= 0)++contpos;else++contneg;}printf ("resultado de números positivos digitados: ", contpos);printf ("resultado de números negativos digitados: ", contneg);}embora tenha se dado esta solução, pode-se fazer de inúmeras outras formas, todas a gosto do programador.em resumo, o código reflete que:o while indica um enquanto, ou seja, enquanto o num digitado for diferente de 0, será feito o laço contido no while;os printf indicam uma mensagem que será exibida no console;o scan recebe o número digitado;o contpos e o contneg farão a contagem dos números digitados positivos e negativos, respectivamente;- o if indica um se, ou seja, se num maior ou igual a 0, o número irá para a contagem de contpos, se não (else), para a contagem de contneg.