Mihran Hovsepyan
En mi programa, estoy ejecutando el comando dado y obteniendo resultados (registro y estado de salida). Además, mi programa debe admitir comandos específicos de shell (es decir, comandos que contienen caracteres específicos de shell ~(tild),|(pipe),*). Pero cuando trato de correr sh -c ls | wc
en mi directorio de inicio a través de mi programa falló y su estado de salida fue 32512, también en stderr stream "sh: ls | wc: command not found"
fue impreso.
Pero lo interesante es que el comando sh -c ls | wc
funciona correctamente si lo ejecuto en Shell.
¿Cuál es el problema? O más preferible, ¿cómo puedo ejecutar comandos específicos de shell a través de mi programa (es decir, qué comando con qué parámetros debo ejecutar)?
La siguiente parte del código está en la parte secundaria después de fork(). Ejecuta el comando.
tokenized_command
es std::vector<std::string>
donde en mi caso "sh", "-c", "ls", "|", "wc"
están almacenados, también he intentado almacenar allí "sh", "-c", "\"ls | wc\""
pero el resultado es el mismo. command
es char *
donde se almacena la línea de comando completa.
boost::shared_array<const char *> bargv(new const char *[tokenized_command.size() + 1]);
const char **argv = bargv.get();
for(int i = 0; i < tokenized_command.size(); ++i)
{
argv[i] = tokenized_command[i].c_str();
printf("argv[%d]: %s\n", i, argv[i]); //trace
}
argv[tokenized_command.size()] = NULL;
if(execvp(argv[0], (char * const *)argv) == -1)
{
fprintf(stderr, "Failed to execute command %s: %s", command, strerror(errno));
_exit(EXIT_FAILURE);
}
PD
yo se que usando system(command)
en cambio execvp
puede resolver mi problema. Pero system()
espera hasta que finalice el comando, y esto no es lo suficientemente bueno para mi programa. Y también estoy seguro de que en la implementación de system()
se usa una de las funciones de la familia exec, por lo que el problema se puede resolver a través de exec
también, pero no sé cómo.
ikegami
execvp
toma una ruta a un ejecutable y argumentos con los que ejecutar ese ejecutable. No toma comandos de Bourne Shell.
ls | wc
es un comando de Bourne Shell (entre otros), y no se puede desglosar en la ruta a un ejecutable y algunos argumentos debido al uso de una canalización. Esto significa que no se puede ejecutar usando execvp
.
Para ejecutar un comando de Bourne Shell usando execvp
hay que ejecutar sh
y pasar -c
y el comando para argumentos.
Así que quieres ejecutar ls | wc
usando execvp
.
char *const argv[] = {
"sh",
"-c", "ls | wc", // Command to execute.
NULL
};
execvp(argv[0], argv)
aparentemente lo intentaste
char *const argv[] = {
"sh",
"-c", "ls", // Command to execute.
"|", // Stored in called sh's $0.
"wc", // Stored in called sh's $1.
NULL
};
Eso sería lo mismo que el comando Bourne Shell sh -c ls '|' wc
.
Y ambos son muy diferentes al comando de shell. sh -c ls | wc
. Eso sería
char *const argv[] = {
"sh",
"-c", "sh -c ls | wc", // Command to execute.
NULL
};
pareces pensar |
y wc
se pasan a la sh
pero ese no es el caso en absoluto. |
es un carácter especial que da como resultado una canalización, no un argumento.
En cuanto al código de salida,
Bits 15-8 = Exit code.
Bit 7 = 1 if a core dump was produced.
Bits 6-0 = Signal number that killed the process.
32512 = 0x7F00
Por lo tanto, no murió debido a una señal, no se produjo un volcado de memoria y salió con el código 127 (0x7F).
No está claro qué significa 127, por lo que debería ir acompañado de un mensaje de error. Intentaste ejecutar el programa ls | wc
pero no existe tal programa.
-
No, recibo un mensaje de error. Siento no haberlo puesto aquí.
sh: ls | wc: command not found
este es el mensaje/– Mihran Hovsepyan
12 de abril de 2011 a las 16:53
-
@Mihran Hovsepyan, está intentando ejecutar el archivo llamado “
ls | wc
“en lugar del comando Bourne Shell”ls | wc
“. Si desea ejecutar un comando de Bourne Shell, debe iniciar un Bourne Shell y pasarle el comando.sh -c 'ls | wc'
.– ikegami
12 de abril de 2011 a las 17:47
-
No quiero la cáscara del almuerzo. No quiero ejecutar comandos específicos de shell desde mi programa.
– Mihran Hovsepyan
13 de abril de 2011 a las 5:23
-
@Mihran Hovsepyan. No está claro lo que quieres decir con eso. Si quiere evitar ejecutar un shell, entonces simplemente no puede ejecutar
ls | wc
. Si quiere decir que quiere hacer que el shell sea configurable, realmente no veo el punto, pero nada lo detiene.– ikegami
13 de abril de 2011 a las 7:47
-
@Mihran Hovsepyan. Si desea evitar ejecutar un shell, deberá iniciar dos procesos (
ls
en uno,wc
en otro), creando una tubería entre ellos en el proceso. También tendrás que gestionar la finalización de dos procesos en lugar de uno. Incluso podría ser más fácil implementar la funcionalidad que desea dels
ywc
tú mismo.– ikegami
13 de abril de 2011 a las 7:50
deberías ejecutar sh -c 'ls | wc'
.
Opción -c
espera un comando en forma de cadena. En shell, por supuesto, está funcionando, porque no hay diferencia entre el desove ls
y redirigir la salida a wc
y lanzamiento ls | wc
en capa separada.
-
En realidad, probablemente estaba generando un shell separado para ejecutar
ls
y también generando unwc
para recibir su salida.– Jonathan
12 de abril de 2011 a las 16:39
-
Sí, lo sé, simplemente no lo subrayé.
– pajtón
12 de abril de 2011 a las 16:42
Proporcione un código que muestre cómo está ejecutando el comando de shell y recopilando el resultado y el estado de salida.
–Oliver Charlesworth
12 de abril de 2011 a las 16:14
no vi nada relacionado con el
c
oc++
etiquetas, así que las eliminé.– Sam Molinero
12 de abril de 2011 a las 17:01
He añadido algo relacionado con el
c
yc++
.– Mihran Hovsepyan
12 de abril de 2011 a las 17:03