Stop and restart a loop in Bash [duplicate] - bash

This question already has answers here:
How do I suspend and resume a sequence of commands in Bash?
(1 answer)
Run one command after another, even if I suspend the first one (Ctrl-z)
(2 answers)
Closed 5 years ago.
After running the following command...
$ for i in {1..10}; do sleep 3; echo $i; done
...if I wait a few seconds and hit Ctl+Z, then I get the following:
1
2
^Z
[1]+ Stopped sleep 3
Now if I use fg to resume the process, it resumes the sleep 3 part of the loop, but does not finish the loop:
$ fg
sleep 3
$
Is there a way to stop the process such that the loop can be continued later?

As other mentioned you need to start new sub-shell with (for i in {1..10}; do sleep 3; echo $i; done)
You can suspend with ctrl+z. If you run jobs command, you should see the suspended jobs. Then resume it via fg or bg commands
Jsfiddle:http://jsfiddle.net/lakshmipathi/chccLdLt/3/

Related

Bash: check job is finished

Theoretical question. Can someone explain me why jobs keep returning Done when it's already done?
root#test:~# cat 1.sh
#!/bin/bash
sleep 5 &
while true; do
echo $(jobs) && sleep 1
done
root#test:~# ./1.sh
[1]+ Running sleep 5 &
[1]+ Running sleep 5 &
[1]+ Running sleep 5 &
[1]+ Running sleep 5 &
[1]+ Running sleep 5 &
[1]+ Done sleep 5
[1]+ Done sleep 5
[1]+ Done sleep 5
[1]+ Done sleep 5
^C
GNU bash, version 5.0.3(1)-release (x86_64-pc-linux-gnu)
Because job control is disabled in scripts, bash ignores signal SIGCHLD and is not notified (and doesn't want to) about terminating background processes.
Because jobs is executed inside a subshell, the parent shell environment doesn't know that the last jobs already checked the child exit status and that the child terminated. Because of that, each time a new subshell is created, it's fresh environment is not aware that the message was printed, so it prints another one.

restart program if it outputs some string

I want to loop a process in a bash script, it is a process which should run forever but which sometimes fails.
When it fails, it outputs >>747;3R to its last line, but keeps running.
I tried (just for testing)
while [ 1 ]
do
mono Program.exe
last_pid=$!
sleep 3000
kill $last_pid
done
but it doesn't work at all, the process mono Program.exe just runs forever (until it crashes, but even then my script does nothing.)
$! expands to the PID of the last process started in the background. This can be seen with:
cat test
sleep 2
lastpid=$!
echo $lastpid
~$ bash -x test
+ sleep 2
+ lastpid=
+ echo
vs
~$ cat test
sleep 2 &
lastpid=$!
echo $lastpid
:~$ bash -x test
+ lastpid=25779
+ sleep 2
+ echo 25779
The fixed version of your script would read:
while true; do
mono Program.exe &
last_pid=$!
sleep 3000
kill $last_pid
done
Your version was running mono Program.exe and then sitting there. It didn't make it to the next line as it was waiting for the process to finish. Your kill command then didn't work as $! never populated (wasn't a background process).

Repeatedly running multiple commands at an interval using a script [duplicate]

This question already has answers here:
executing shell command in background from script [duplicate]
(4 answers)
Closed 6 years ago.
I want to repeatedly run multiple commands at a time interval using a script.
I tried this
----------------test_script---------------
while true;do
ls -l >>output.txt
sleep 3
done
while true;do
cat file.txt
sleep 5
done
i want to run both while loops at same time .When i run the above script ,only first while loop is running and the output of ls -l is redirected to the file .How i can execute both while loops simultaneously from the script
One way to do is run one of the loops in the background and other in the fore like below.
#!/bin/bash
while true;do
ls -l >>output.txt
sleep 3
done & # Runs the first while loop in the background and passes to the next while loop
while true;do
cat file.txt
sleep 5
done

Unable to run infinite loop process in background in terminal. [duplicate]

This question already has an answer here:
bg / fg inside a command line loop
(1 answer)
Closed 6 years ago.
I was trying out the commands as the video of Season1 Episode8 Processes and Jobs progressed. I have a bash terminal running on Ubuntu 16.04.
while true; do echo ping; sleep 1; done
^Z
Instead of getting:
[1]+ Stopped while true; do echo ping; sleep 1; done
I get:
[1]+ Stopped sleep 1
bg%1 further gives only
[1]+ sleep 1 &
instead of a series of ping in 1s interval in the background
Any ideas on why this happens and how to actually get a series of ping in 1s interval in the background would be appreciated.
Try:
bash <<< 'while true; do echo ping; sleep 1; done'
Result:
^Z
[1]+ Stopped bash <<< 'while true; do echo ping; sleep 1; done'
Or using a subshell:
(while true; do echo ping; sleep 1; done)
Result:
^Z
[1]+ Stopped ( while true; do
echo ping; sleep 1;
done )
Run your command with a & at the end, instead of stopping it. ^Z is too narrow to use with commands like this.
You run the command by either adding an & at the end which is easier you might find more trouble to end the process.
admin1#mysys:~$ while true; do echo ping; sleep 1; done&
[2] 14169
admin1#mysys:~$ ping
ping
ping
^C
admin1#mysys:~$ ping
ping
ping
^C
admin1#mysys:~$ ping
ping
ping
ping
^C
admin1#mysys:~$ ping
kill 14169
admin1#mysys:~$
As you can see, you will have to Cntrl + D or kill the process to stop it.
Another option would be to use 'screen'
Assuming you have screen installed, enter the terminal and execute the command 'screen'
Then you can execute the command:
while true; do echo ping; sleep 1; done
and then press Cntrl A and then D (keeping Cntrl pressed itself). This will detach you from screen and you can do whatever you want and the command will be executed in the background.
At any time you can list the current screen executing
screen -ls
and then connect to the screen back by executing
screen -r screen_name
This sounds a bit complicated but is a better way to handle things. You can find more details Here
Borrowing from [ this ] answer, Ctrl-Z generates the [ TSTP ] signal to your process and stopping the process is clearly not your intention.
To run a process in the background, do
process >/dev/null &
# Here the '>/dev/null' suppresses any output from the command
# popping up in the screen, this may or may not be desirable
# The & at the end tells bash that the command is to be run in backgroud
For example
$ ping -c 100 192.168.0.1 >/dev/null &
[1] 2849
Note the two numbers [1] & 2849 that bash gave you. The first one is the background process number. Say, if you wish to bring this process to the foregroud, you could use this number
fg 1 # Here fg stands for foreground
The second number is the process ID ie 2849. Say, you wish to terminate the
process, you could do it like below :
kill -9 2849 #-9 is for SIGKILL
Edit
In your case, you could wrap the loop inside a function like below
while_fun() {
while true
do
echo "PING"
done
}
and do
while_fun >dev/null &
Or do
while true
do
echo "PING"
done >/dev/null &
You could try something like this:
while true; do
echo ping 1
sleep 1
done;
Note that I have only placed semicolon ; on done - marking the end of statement. I tried this on my terminal and behaves as you expect.

Display a progress bar or spinner while a command is running in bash script [duplicate]

This question already has answers here:
Using Bash to display a progress indicator [duplicate]
(12 answers)
Closed 7 years ago.
I have a bash script that ends as follows:
trap "exit" INT
for ((i=0; i < $srccount; i++)); do
echo -e "\"${src[$i]}\" will be synchronized to \"${dest[$i]}\""
echo -e $'Press any key to continue or Ctrl+C to exit...\n'
read -rs -n1
#show_progress_bar()
rsync ${opt1} ${opt2} ${opt3} ${src[$i]} ${dest[$i]}
done
I need a command or a function such as show_progress_bar() that put . (a dot) in the stdout every one second while rsync command is running (or a rotating / that rotates as / - \ | sequence while rsync is running).
Is it possible? Do I need to wrote such function myself, or there is available scripts for this purpose?
It's not pretty, but it works:
~$ while true; do echo -n .; sleep 1; done & sleep 3; kill %-; wait; echo;
[1] 26255
...[1]+ Terminated while true; do
echo -n .; sleep 1;
done
(exchange the "sleep 3" for your actual work)
It works like this:
The while loop runs as a background job.
Meanwhile, your work ("sleep 3" in my example) runs in the foreground.
When the work is done, "kill %-" kills the echo loop.
Then we wait for the job to terminate, and echo a newline, just in case.
Like I said, it's not pretty. And there's probably a much better way to do it. :)
EDIT: For example, like the answer here: Using BASH to display a progress (working) indicator

Resources