Como criar um monte de processos em segundo plano em terminais terminadores e depois matá-los no bash

2

Estou tentando escrever um script em lote que crie novos terminais de terminação e, em seguida, execute um processo em cada um deles. Eu quero que eles continuem correndo em segundo plano até eu decidir matá-los.

Eu quero que o primeiro seja executado por 10 segundos e depois crie um monte de outros processos terminadores simultaneamente.

Esta primeira parte funciona bem, mas agora eu quero, no final, poder pressionar enter e enviar um SIGINT para cada processo que eu iniciei. Eu não consigo descobrir um comando que funcione para esse propósito.

#!/bin/sh
echo "Running Teleop... (MAY TAKE SEVERAL SECONDS TO INITIALIZE)"

terminator -T "gazebo" -e "roslaunch cob_bringup_sim robot.launch 
robot:=cob4-8 robot_env:=ipa-apartment; bash" &

#wait 10 secons before starting nav and rviz otherwise will get error
((sleep 10) &&
(terminator -T "navigation" -e "roslaunch cob_navigation_global 
2dnav_ros_dwa.launch robot:=cob4-5 robot_env:=ipa-apartment; bash" &
terminator -T "rviz" -e "roslaunch cob_navigation_global rviz.launch; 
bash" &
terminator -T "arm_controller" -e "roslaunch cob_moveit_bringup 
demo.launch rviz_tutorial:=true robot:=cob4-8; bash" &
terminator -T "control_nodes" -e "cd catkin_ws; rosrun first_pkg 
control_nodes; bash" &
terminator -T "controller" -e "cd catkin_ws; rosrun first_pkg 
controller; bash" &
terminator -T "joystick" -e "rosrun joy joy_node; bash" &
#spawn objects
terminator -T "spawn_objects_launch" -e "roslaunch 
cob_default_env_config upload_object_locations.launch robot_env:=ipa- 
apartment; rosrun cob_bringup_sim spawn_object.py tomato_sauce; 
bash")) &

(
echo Press any key to to shutdown all processes
read varname
echo Shutting down...
#terminating all child processes
)

Estes são comandos do ROS, mas eu suponho que não há diferença entre eles e comandos genéricos neste caso. Eu percebo que o código é bastante confuso e, se houver algum outro problema, eu ficaria feliz em ouvi-lo. Obrigado!

    
por Benjy Wexler 27.09.2018 / 22:31

1 resposta

2

Quando executado de forma não interativa (por exemplo, em um script), o bash desabilita o controle de tarefas, de forma que métodos fáceis de eliminar processos em segundo plano, como aqueles em Mate todos os trabalhos em segundo plano ou Como matar todos os empregos no bash? trabalho por padrão.

A primeira coisa que gostaria de fazer é garantir que você esteja executando o bash alterando a linha sh-bang para:

#!/bin/bash

Em seguida, vamos ativar o controle de tarefas (também conhecido como " modo monitor ") para que possamos usar uma das soluções fáceis daquelas perguntas anteriores:

set -m

Em seguida, eu simplificaria a maior parte da sua atividade de subshell; você não precisa deles. Com comandos simplificados, apenas para demonstrar o ponto:

#wait 10 seconds before starting nav and rviz otherwise will get error
sleep 10 || exit
terminator -T "navigation ... bash" &
terminator -T "rviz ... bash" &
...
terminator -T "spawn_objects_launch" &

echo Press any key to to shutdown all processes
read varname
echo Shutting down...

Você não precisa iniciar um subshell inteiro (e criar um plano de fundo) para todos os processos do terminador. Você não precisa executar o sleep 10 em um subshell. Você não realmente precisa testar o código de retorno de sleep 10 para encadear os comandos subsequentes, com && . Eu adaptei o código para corresponder ao comportamento existente: se o comando sleep falhar (digamos, você pressionar Control-C), o script sairá e não iniciará os processos subsequentes do terminador.

Por último, adicione o código para eliminar os processos filhos:

...
terminator -T "spawn_objects_launch" &

echo Press ENTER to shutdown all processes
read 
echo Shutting down...
kill $(jobs -p)

Reescrevi o aviso; você precisaria digitar (quase) qualquer tecla e então pressionar ENTER para que o comando read possa ver sua entrada, então eu simplesmente sugiro que o usuário pressione ENTER. Em seguida, o comando read aceita um nome de variável, mas há uma variável padrão chamada REPLY que será usada se você não especificar seu próprio nome de variável, portanto, se isso for mais óbvio para você, essa é outra opção simplifique o código.

    
por 28.09.2018 / 03:52