I am trying to execute some commands and one of which will not come back to console and need to explicitly bring it using ctrl+ c. After that I need to execute some more commands in that script.
expect "$ "
send "sh /root/jboss-eap-6.3/bin/standalone.sh\r"
set timeout 10
expect "$ "
I have to run other commands after executing standalone.sh script. But it will hold and not come back to console.
I tried
trap {
send \x03
send_user "You pressed Ctrl+C\n"
} SIGINT
.
But that also didn't worked.
Thanks in advance.
There are all sorts of ways to kill a process in bash. If you by some chance know the name of your (jboss eap) process you could run pkill processName, killall processName or kill pidof processName instead of trying to send key-strokes.
Related
I wrote an expect script like this:
#!/usr/bin/expect -f
spawn sql "user=xx dbname=xx"
interact
After I entered the sql client, I can't send the SIGTSTP signal by ctrl + z to make the current process suspend and go to the background.
The terminal will only show:
=> ^Z
What should I do to make ctrl + z achieve the above purpose?
The manual of expect gives the recipe:
During interact, raw mode is used so that all characters may be passed to the current process. If the current process does not catch job control signals, it will stop if sent a stop signal (by default ^Z). To restart it, send a continue signal (such as by "kill -CONT "). If you really want to send a SIGSTOP to such a process (by ^Z), consider spawning csh first and then running your program. On the other hand, if you want to send a SIGSTOP to Expect itself, first call interpreter (perhaps by using an escape character), and then press ^Z.
So, you may be able to do something like:
#!/usr/bin/expect -f
spawn /bin/sh
exp_send "psql hostaddr=xxxx port=xxxx user=xx dbname=xx\r"
interact
For example, let's consider the following interactive shell script named interact.sh:
#!/bin/sh
read -p "First name: " fname
read -p "Last name: " lname
echo "you entered: $fname $lname"
And the following expect script named script.exp to automate the previous one:
#!/usr/bin/expect -f
spawn /bin/sh
exp_send "./interact.sh\r"
interact
We launch the latter:
$ ./script.exp
spawn /bin/sh
./interact.sh
$ ./interact.sh
First name: Stack
Last name: ^Z (we entered CTRL-Z here)
[1]+ Stopped(SIGTSTP) ./interact.sh
sh-4.4$ jobs
[1]+ Stopped(SIGTSTP) ./interact.sh
sh-4.4$ fg
./interact.sh
Overflow
you entered: Stack Overflow
$ exit
exit
$
I try to send a signal from one terminal A to another terminal B. Both run an interactive shell.
In terminal B, I trap signal SIGUSR1 like so :
$ trap 'source ~/mycommand' SIGUSR1
Now in terminal A I send a signal like so :
$ kill -SIGUSR1 pidOfB
Unfortunately, nothing happens in B. If I want to have my command executed, I need to switch to B and either input a new command or press enter.
How can I avoid this drawback and immediately execute my command instead ?
EDIT :
It's important to note that I want to interact directly with the interactive shell in terminal B from terminal A.
For this reason, every solution where the trap command would be executed in a subshell would not work for me...
Also, terminal B must stay interactive.
The shell may simply be stuck in a blocking read, waiting for command-line input. Hitting enter causes the handler to execute before the entered command. Running a non-blocking command like wait:
$ sleep 60 & wait
then sending the signal causes wait to terminate immediately, followed by the output of the handler.
Based on the answers and my numerous attempt to solve this, I don't think it's possible to catch a trap signal immediately in an interactive bash terminal.
For it to trigger, there must be an interaction from the user.
This is due to the readline program blocks until a newline is entered. And there is no way to stop this read.
My solution is to use dtach, a small program that emulate the detach feature of screen.
This program can run a fully interactive shell and features in its last version a way to communicate via a custom socket to this shell (or whatever program you launch)
To start a new dtach session running an interactive bash, in terminal B :
$ dtach -a /tmp/MySocket bash -i
Now from terminal A, we can send a message to the bash session in terminal B like so :
$ echo 'echo hello' | dtach -p /tmp/MySocket
In terminal B, we now see :
$ echo hello
hello
To expand on that if I now do in terminal A :
$ trap 'echo "cd $(pwd)" | dtach -p /tmp/MySocket' DEBUG
I'll have the directory of the two terminals synced
PS :I'd still like to know if there is a way to do this in pure bash
I use a similar trap so that periodically I can (from a separate cron job) force all idle bash processes to do a 'history -a'. I found that if I trap SIGALRM instead of SIGUSR1, then the bash blocking read seems not to be a problem: the trap runs now, rather than next time one hits return. I tried SIGINT, but that caused an annoying "^C", followed by a new prompt line, to be displayed. I haven't yet found any drawbacks of using SIGALRM, but perhaps they will arise.
It may be buffering.
As a test, try installing a loop trigger. In window A:
{ trap 'ls' USR1; while sleep 1; do echo>/dev/null;done } &
[1] 7316
in window B:
kill -usr1 7316
back in window A the ls is firing when the loop does an echo.
Don't know if that will help, but it's something.
I am using an Expect script to automate the installation of a program. Because of an issue with one of the install dependencies, I need to pause the installation process at a specific point to edit the db.properties file. Once that file is changed, I can resume the installation process. I can spawn a new process in the middle of the installation to do this, but I get the "spawn id exp5 not open" error after closing that process.
db_edit.sh edits the appropriate file:
#!/usr/bin/sh
filename=db.properties
sed -i "s/<some_regex>/<new_db_info>/g" $filename
My automated installation script spawns the above script in the middle of its execution:
#!/usr/bin/expect
# Run the installer and log the output
spawn ./install.bin
log_file install_output.log
# Answer installer questions
# for simplicity, let's pretend there is only one
expect "PRESS <ENTER> TO CONTINUE:"
send "\r"
# Now I need to pause the installation and edit that file
spawn ./db_edit.sh
set db_edit_ID $spawn_id
close -i $db_edit_ID
send_log "DONE"
# Database Connection - the following must happen AFTER the db_edit script runs
expect "Hostname (Default: ):"
send "my_host.com\r"
# more connection info ...
expect eof
The output log install_output.log shows the following error:
PRESS <ENTER> TO CONTINUE: spawn ./db_edit.sh^M
DONEexpect: spawn id exp5 not open
while executing
"expect "Hostname (Default: ):""^M
The database info has been modified correctly, so I know the script works and it is indeed spawned. However, when I close that process, the spawn id of the installation process is also apparently closed, which causes the spawn id exp5 not open error.
Also curious is that the spawn appears to happen before it should. The response to "PRESS <ENTER>" should be "\r" or ^M to indicate that ENTER was sent.
How can I fix this to resume the installation script after closing db_edit.sh?
There is no need to automate any interactivity with that script, so don't use spawn
exec db_edit.sh
This way, you're not interfering with the spawn_id of the currently spawned process.
i'll need some help to get back the prompt, right now i'm executing this block and don't throw me back the prompt, i'm using & at the end for run this command as a background task. how can get back to prompt after execute the script.
#!/bin/sh
sudo su - user << EOF
nohup program -p4xxx &
EOF
nota: if i press ctrl + c - kill the program.
Thank you in advance.
Without testing, I'm wondering if you want this:
#!/bin/bash
nohup sudo -u user program -p4xxx &
disown
That will background the sudo process, and disassociate it from the calling shell (the script).
(From https://askubuntu.com/questions/121559)
After you start a process (job), you can still do other things. You might want to write these down as a cheat sheet.
Ctrl+c Kill the running process (foreground job)
Ctrl+z Pause running process (foreground job) and return to the prompt
Type jobs Shows you all background jobs on the terminal
Type bg Makes the last paused job continue in the background
Type fg Returns the last pause job to the foreground
You can also type bg or fg with a number after, like fg 3. This will bring job #3 to the foreground.
Two alternative:
Bring background job foreground with fg and send signal with
ctrl+c
Directly kill background process(correspond to program job)
with pkill program
I am working with programs that use CTRL-C to stop a task, and what I want to do is to run that task for certain number of minutes and then have it stop like CTRL-C was pressed. The reason why I want it to stop like ctrl+c was pressed is because it auto saves when you stop the program instead of killing it and possibly losing the saved data.
edit; I don't want to use cron unless if it stops my script it will have the program save the data, I am hoping to accomplish this inside the shell script.
The trap statement catches these sequences and can be programmed to execute a list of commands upon catching those signals.
-#!/bin/bash
trap "echo Saving Data" SIGINT
while :
do
sleep 60
done
For Information on Traps : http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html
Using timeout command to send SIGINT after 60 seconds:
timeout --signal=INT 60 /path/to/script.sh params
If you need to intercept ctrl+c, you should use the trap builtin, like this :
cleanup(){ # do something...; }
trap 'cleanup' 2
# rest of the code
2 on trap line is the SIGINT signal sended by ctrl+c, see man 7 signals
Try the following:
#!/bin/bash
set -m
/path/to/script.sh params &
set +m
bg_pid=$!
sleep 60
kill -2 $bg_pid
This should allow you to send SIGINT to a backgrounded process using Job Control and the set builtin