Quiero iniciar el proceso (por ejemplo, myCommand) y obtener su pid (para permitir matarlo más tarde).
Intenté ps y filtro por nombre, pero no puedo distinguir el proceso por nombres
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Porque los nombres de los procesos no son únicos.
Puedo ejecutar el proceso por:
myCommand &
Descubrí que puedo obtener este PID:
echo $!
¿Hay alguna solución más simple?
Me encantaría ejecutar myCommand y obtener su PID como resultado de un comando de línea.
myprogram
habría sido impresionante&
como la línea anterior, de lo contrario, el eco básicamente vuelve en blanco.command & echo $!
congela la ejecución en este paso :(Envuelva el comando en un pequeño script
fuente
Puede usar
sh -c
yexec
para obtener el PID del comando incluso antes de que se ejecute.Para comenzar
myCommand
, para que su PID se imprima antes de que comience a ejecutarse, puede usar:Cómo funciona:
Esto inicia un nuevo shell, imprime el PID de ese shell y luego usa el
exec
incorporado para reemplazar el shell con su comando, asegurando que tenga el mismo PID. Cuando su shell ejecuta un comando con elexec
builtin incorporado, en realidad se está convirtiendo en ese comando , en lugar del comportamiento más común de bifurcar una nueva copia de sí mismo, que tiene su propio PID separado y que luego se convierte en el comando.Considero que esto es mucho más simple que las alternativas que involucran ejecución asincrónica (con
&
), control de trabajo o búsqueda conps
. Esos enfoques están bien, pero a menos que tenga una razón específica para usarlos, por ejemplo, tal vez el comando ya se esté ejecutando, en cuyo caso buscar su PID o usar el control de trabajo tendría sentido, sugiero que considere esto primero. (Y ciertamente no consideraría escribir un script complejo u otro programa para lograr esto).Esta respuesta incluye un ejemplo de esta técnica.
Algunas partes de ese comando podrían omitirse ocasionalmente, pero generalmente no.
Incluso si el shell que está utilizando es de estilo Bourne y, por lo tanto, es compatible
exec
con esta semántica, generalmente no debe intentar evitar el usosh -c
(o equivalente) para crear un nuevo proceso de shell separado para este propósito, porque:myCommand
, no hay ningún shell esperando para ejecutar comandos posteriores.sh -c 'echo $$; exec myCommand; foo
no podría intentar ejecutarsefoo
después de reemplazarse por sí mismomyCommand
. A menos que esté escribiendo un script que ejecute esto como su último comando, no puede simplemente usarloecho $$; exec myCommand
en un shell donde está ejecutando otros comandos.(echo $$; exec myCommand)
puede ser sintácticamente mejor quesh -c 'echo $$; exec myCommand'
, pero cuando se ejecuta en el$$
interior(
)
, proporciona el PID del shell principal, no del subshell en sí. Pero es el PID del subshell el que será el PID del nuevo comando. Algunos shells proporcionan sus propios mecanismos no portátiles para encontrar el PID del subshell, que puede usar para esto. En particular, en Bash 4 ,(echo $BASHPID; exec myCommand)
funciona.Finalmente, tenga en cuenta que algunos shells realizarán una optimización donde ejecutan un comando como si
exec
(es decir, renunciaran a bifurcar primero) cuando se sabe que el shell no necesitará hacer nada después. Algunos shells intentan hacer esto cada vez que es el último comando que se ejecuta, mientras que otros solo lo hacen cuando no hay otros comandos antes o después del comando, y otros no lo hacen en absoluto. El efecto es que si olvida escribirexec
y simplemente usash -c 'echo $$; myCommand'
, a veces le dará el PID correcto en algunos sistemas con algunos shells. Recomiendo no depender nunca de ese comportamiento y, en su lugar, siempre incluirexec
cuándo es lo que necesita.fuente
myCommand
, necesito establecer una serie de variables de entorno en mi script bash. ¿Se trasladarán al entorno en el queexec
se ejecuta el comando?exec
comando. Sin embargo, este enfoque no funciona cuando semyCommand
inician otros procesos, con los que debe trabajar; cuando emito unkill -INT <pid>
dóndepid
se obtuvo de esta manera, la señal no alcanza los subprocesos iniciados pormyCommand
, mientras que si ejecutomyCommand
en la sesión actual y Ctrl + C, las señales se propagan correctamente.sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
No conozco ninguna solución más simple, ¡pero no estoy usando $! ¿suficientemente bueno? Siempre puede asignar el valor a alguna otra variable si lo necesita más tarde, como lo han dicho otros.
Como nota al margen, en lugar de canalizar desde ps podría usar
pgrep
opidof
.fuente
use exec de un script bash después de registrar el pid en un archivo:
ejemplo:
supongamos que tiene un script llamado "forever.sh" que desea ejecutar con los argumentos p1, p2, p3
código fuente forever.sh:
crear un reaper.sh:
ejecutar forever.sh a través de reaper.sh:
forever.sh no hace más que registrar una línea en syslog cada 5 segundos
ahora tienes el pid en /var/run/forever.sh.pid
y forever.sh se está ejecutando aok. syslog grep:
puedes verlo en la tabla de procesos:
fuente
exec "$@"
lugar deexec $*
. Técnicamente, lo que necesita preservar no es el espacio en blanco, sino las apariciones de los caracteres en el parámetro de shell IFS (que por defecto es espacio, tabulación y nueva línea).En el shell bash, una alternativa
$!
podría ser eljobs -p
incorporado. En algunos casos el!
en$!
se interpreta por la cáscara antes de (o en lugar de) la expansión de variables, lo que lleva a resultados inesperados.Esto, por ejemplo, no funcionará:
mientras que esto:
fuente
Puedes usar algo como:
O
Los dos comandos pueden ser uniones usando
;
o&&
. En el segundo caso, el pid se establecerá solo si el primer comando tiene éxito. Puede obtener la identificación del proceso$pid
.fuente
$!
después&&
o;
nunca le dará el PID del proceso iniciado para el lado izquierdo del separador de comandos.$!
solo está configurado para procesos iniciados de forma asincrónica (por ejemplo, generalmente con&
algunos shells pero también tienen otros métodos)Esta es una respuesta un poco hack-y y probablemente no funcionará para la mayoría de las personas. También es un gran riesgo de seguridad, así que no lo hagas a menos que estés seguro de que estarás seguro y las entradas están desinfectadas y ... bueno, ya tienes la idea.
Compile el pequeño programa C aquí en un binario llamado
start
(o lo que quiera), luego ejecute su programa como./start your-program-here arg0 arg1 arg2 ...
En pocas palabras, esto imprimirá el PID y
stdout
luego cargará su programa en el proceso. Aún debe tener el mismo PID.fuente
stdout
queda clara, no parece estar registrada en este ejemplo:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
sleep 10 & PID_IS=$!; echo $PID_IS