bash - How to keep launching a program until it exits with 0 - linux

Wrote a python script that does a task that may be running for a few hours. Since it communicates with a remote server, the script may fail if there's a connection error. What I'd like to do is to keep relaunching it if its exit code is not 0. Is it possible with bash?
Some pseudo-C if my wording is not clear:
int exitcode;
do
{
exitcode = MyPythonScript();
} while (exitcode != 0);

until MyPythonScript
do
: Nothing
done
That exits when the command exits with a true (success) status. You can put a sleep, or an error report, or anything else you want in the body of the loop in place of the 'do nothing but always succeed' command :. You can add arguments to the script as desired, of course (and I/O redirections, etc).

Related

In Node.js How can I stop the script execution, successfully write an error message to the console, and then exit the script?

I'm running Node.js using VS Code on Windows.
Upon detecting an error condition, how can I completely stop the execution of the script at that point, except for writing a final error message to the console?
I would need to wait until there is a confirmation that the error message has been successfully displayed to the user, and then completely exit the rest of the script without any further execution of the the code past the successful console write?
As noted in the nodejs docs, the safe way to exit whitout truncating the outuput is to set the process exitCode and then throw an unhadled exception:
// How to properly set the exit code while letting
// the process exit gracefully.
if (someConditionNotMet()) {
console.log('final error message');
process.exitCode = 1;
throw new Error('Exit'); // must me NOT handled by a try/catch
}
Otherwise, if you want to exit immediately, you can just call process.exit(1), but you cannot be sure that every pending output will be displayed: some text output can be async.

Spawn Expect from a perl thread

I am working on a script which needs to spawn an Expect process periodically (every 5 mins) to do some work. Below is the code that I have that spawns an Expect process and does some work. The main process of the script is doing some other work at all times, for example it may wait for user input, because of that I am calling this function 'spawn_expect' in a thread that keeps calling it every 5 minutes, but the issue is that the Expect is not working as expected.
If however I replace the thread with another process, that is if I fork and let one process take care of spawning Expect and the other process does the main work of the script (for example waiting at a prompt) then Expect works fine.
My question is that is it possible to have a thread spawn Expect process ? do I have to resort to using a process to do this work ? Thanks !
sub spawn_expect {
my $expect = Expect->spawn($release_config{kinit_exec});
my $position = $expect->expect(10,
[qr/Password.*: /, sub {my $fh = shift; print $fh "password\n";}],
[timeout => sub {print "Timed out";}]);
# if this function is run via a process, $position is defined, if it is run via a thread, it is not defined
...
}
Create the Expect object beforehand (not inside a thread) and pass it to a thread
my $exp = Expect->spawn( ... );
$exp->raw_pty(1);
$exp->log_stdout(0);
my ($thr) = threads->create(\&login, $exp);
my #res = $thr->join();
# ...
sub login {
my $exp = shift;
my $position = $exp->expect( ... );
# ...
}
I tested with multiple threads, where one uses Expect with a custom test script and returns the script's output to the main thread. Let me know if I should post these (short) programs.
When the Expect object is created inside a thread it fails for me, too. My guess is that in that case it can't set up its pty the way it does that normally.
Given the clarification in a comment I'd use fork for the job though.

after calling exec

After calling exec, is it possible to print a message, because I tried and nothing happened. I read some articles about exec but I couldn't find my answer. It replaces the process image with a new one but not creating a new process. Is it something about it? Does it wait for something I mean if I use it in child process, so does it wait for ending child process?
I can give this example:
char *args[6] = { "cat","-b","-t","-v",argv[1],0};
else if(pid == 0){
printf("Child Process ID:%d, Parent ID:%d, Process
Group:%d\n",getpid(),getppid(),getgid());
execv("/bin/cat",args);
printf("AHMET TANAKOL\n");
}
The exec family, like you already read, replaces the process image. That is, it loads the new program, removes your program, and start running the new program in place of your program.
No call to exec functions ever returns, unless there is an error.

How to exit in Node.js

What is the command that is used to exit? (i.e terminate the Node.js process)
Call the global process object's exit method:
process.exit()
From the docs:
process.exit([exitcode])
Ends the process with the specified code. If omitted, exit with a 'success' code 0.
To exit with a 'failure' code:
process.exit(1);
The shell that executed node should see the exit code as 1.
Just a note that using process.exit([number]) is not recommended practice.
Calling process.exit() will force the process to exit as quickly as
possible even if there are still asynchronous operations pending that
have not yet completed fully, including I/O operations to
process.stdout and process.stderr.
In most situations, it is not actually necessary to call
process.exit() explicitly. The Node.js process will exit on its own if
there is no additional work pending in the event loop. The
process.exitCode property can be set to tell the process which exit
code to use when the process exits gracefully.
For instance, the following example illustrates a misuse of the
process.exit() method that could lead to data printed to stdout being
truncated and lost:
// This is an example of what *not* to do:
if (someConditionNotMet()) {
printUsageToStdout();
process.exit(1);
}
The reason this is
problematic is because writes to process.stdout in Node.js are
sometimes asynchronous and may occur over multiple ticks of the
Node.js event loop. Calling process.exit(), however, forces the
process to exit before those additional writes to stdout can be
performed.
Rather than calling process.exit() directly, the code should set the
process.exitCode and allow the process to exit naturally by avoiding
scheduling any additional work for the event loop:
// How to properly set the exit code while letting
// the process exit gracefully.
if (someConditionNotMet()) {
printUsageToStdout();
process.exitCode = 1;
}
From the official nodejs.org documentation:
process.exit(code)
Ends the process with the specified code. If omitted, exit uses the 'success' code 0.
To exit with a 'failure' code:
process.exit(1);
If you're in a Unix terminal or Windows command line and want to exit the Node REPL, either...
Press Ctrl + C twice, or
type .exit and press Enter, or
press Ctrl + D at the start of a line (Unix only)
From the command line, .exit is what you want:
$ node
> .exit
$
It's documented in the REPL docs. REPL (Read-Eval-Print-Loop) is what the Node command line is called.
From a normal program, use process.exit([code]).
It depends on the reason why you're willing to exit node.js process, but in any case process.exit() is the last option to consider. A quote from documentation:
It is important to note that calling process.exit() will force the
process to exit as quickly as possible even if there are still
asynchronous operations pending that have not yet completed fully,
including I/O operations to process.stdout and process.stderr.
In most situations, it is not actually necessary to call
process.exit() explicitly. The Node.js process will exit on it's own
if there is no additional work pending in the event loop. The
process.exitCode property can be set to tell the process which exit
code to use when the process exits gracefully.
Let’s cover possible reasons why you might be willing to exit node.js process and why you should avoid process.exit():
Case 1 - Execution complete (command line script)
If script has reached its end and node interpreter doesn't exit, it indicates that some async operations are still pending. It’s wrong to force process termination with process.exit() at this point. It’s better to try to understand what is holding your script from exiting in expected way. And when you settle this, you can use process.exitCode to return any result to calling process.
Case 2 - Termination because of external signal (SIGINT/SIGTERM/other)
For example, if you’re willing to gracefully shut down an express app. Unlike command line script, express app keeps running infinitely, waiting for new requests. process.exit() will be a bad option here because it’s going to interrupt all requests which are in pipeline. And some of them might be non-idempotent (UPDATE, DELETE). Client will never know if those requests are completed or not on server side and it might be the reason of data inconsistency between client and server. The only good solution is to tell http server to stop accepting new requests and wait for pending ones to finish with server.close():
var express = require('express');
var app = express();
var server = app.listen(80);
process.on( 'SIGTERM', function () {
server.close(function () {
console.log("Finished all requests");
});
});
If it still doesn't exit - see Case 1.
Case 3 - Internal error
It's always better to throw an error, you’ll get a nicely formatted stack trace and error message. Upper levels of code can always decide if they can handle error (catch) or let it crash the process. On the other side, process.exit(1) will terminate process silently and there will be no chance to recover from this. It might be the only “benefit” of process.exit(), you can be sure that process will be terminated.
REPL(Command Line)
Press ctrl + c twice
Type .exit and press enter
Script File
process.exit(code)
Node normally exits with code 0 when no more async operations are pending.
process.exit(1) should be used to exit with a failure code.This will allow us to infer that node didn't close gracefully and was forced to close.
There are other exit codes like
3 - Internal JavaScript Parse Error ( very very rare)
5 - Fatal error in v8 javascript engine
9 - Invalid argument
For full list see node exit codes
I have an application which I wanted to:
Send an email to the user
Exit with an error code
I had to hook process.exit(code) to an exit event handler, or else the mail will not be sent since calling process.exit(code) directly kills asynchronous events.
#!/usr/bin/nodejs
var mailer = require('nodemailer');
var transport = mailer.createTransport();
mail = {
to: 'Dave Bowman',
from: 'HAL 9000',
subject: 'Sorry Dave',
html: 'Im sorry, Dave. Im afraid I cant do <B>THAT</B>.'
}
transport.sendMail(mail);
//process.exit(1);
process.on('exit', function() { process.exit(1); });
As #Dominic pointed out, throwing an uncaught error is better practice instead of calling process.exit([code]):
process.exitCode = 1;
throw new Error("my module xx condition failed");
Press Ctrl + C twice
or .exit.
>
(To exit, press ^C again or type .exit)
>
To exit
let exitCode = 1;
process.exit(exitCode)
Useful exit codes
1 - Catchall for general errors
2 - Misuse of shell builtins (according to Bash documentation)
126 - Command invoked cannot execute
127 - “command not found”
128 - Invalid argument to exit
128+n - Fatal error signal “n”
130 - Script terminated by Control-C
255\* - Exit status out of range
From code you can use process.exit([errorcode]) where [errorcode] is an optional integer (0 is the default to indicate success).
If you're using the Read Eval Print Loop (REPL), you can use Ctrl + D, or type .exit
Alternatively, on Windows or Linux you can use Ctrl + C, Ctrl + C
On Mac the command is Ctrl + Z, Ctrl + Z
adding
process.exit(1);
will do the trick for you
I was able to get all my node processes to die directly from the Git Bash shell on Windows 10 by typing taskkill -F -IM node.exe - this ends all the node processes on my computer at once. I found I could also use taskkill //F //IM node.exe. Not sure why both - and // work in this context. Hope this helps!
Open the command line terminal where node application is running and press Ctrl + C
if you want to exit a node js application from code,
process.exit(); // graceful termination
process.exit(1); // non graceful termination
As process is global object, you don't need to import any module. The following function exits or kills the current node process.
process.exit(code)
process.kill(process.pid)
process.abort()
if you want to exit from node js application then write
process.exit(1)
in your code
The exit in node js is done in two ways:
Calling process.exit() explicitly.
Or, if nodejs event loop is done with all tasks, and there is nothing left to do. Then, the node application will automatically exit.
How it works?
If you want to force the execution loop to stop the process, yo can use the global variable process which is an instance of EventEmitter. So when you call process.exit() you actually emit the exit event that ends all tasks immediately even if there still are asynchronous operations not been done.
process.exit() takes an exit code (Integer) as a parameter. The code 0 is the default and this means it exit with a 'success'. While the code 1 means it exit with a 'failure'.
import mongosse from 'mongoose'
import dotenv from 'dotenv'
import colors from 'colors'
import users from './data/users.js'
import products from './data/products.js'
import User from './models/userModel.js'
import Product from './models/productModel.js'
import Order from './models/orderModel.js'
import connectDB from './config/db.js'
dotenv.config()
connectDB()
const importData = async()=>{
try{
await Order.deleteMany()
await Product.deleteMany()
await User.deleteMany()
const createdUsers = await User.insertMany(users)
const adiminUser = createdUsers[0]._id
sampleProducts = products.map(product =>{
return {...product, user:adiminUser }
})
await Product.insertMany(sampleProducts)
console.log('Data Imported!'.green.inverse)
process.exit() //success and exit
}catch(error){
consolele.log(`${error}`.red.inverse)
process.exit(1) //error and exit
}
}
so here im populating some collections in a db and in the try block if i dont get any errors then we exit it with a success message , so for that we use process.exit() with nothing in the parameter.
If theres an error then we need to exit with an unsuccessfull message so we pass 1 in the parameter like this , process.exit(1).
extra: Here by exiting we mean exiting that typical node js program. eg if this code was in a file called dbOperations.js then the process.exit will exit and wont run any code that follows after process.exit
ctrl+C to terminate present process
ctrl+C twice is to exit REPL shell
ctrl+c to exit from REPL SHELL
You may use process.exit([code]) function.
If you want to exit without a 'failure', you use code 0:
process.exit(0);
To exit with a 'failure' code 1 you may run:
process.exit(1);
The 'failure' code of the failure is specific to the application. So you may use your own conventions for it.
If you're in Windows, go to Task Manager, then go to Processes, look for a process called "node", then click on it with the right button of your mouse and then click the "End Process" option.

Why doesnt SIGINT get caught here?

Whats going on here? I thought SIGINT would be sent to the foreground process group.
(I think, maybe, that system() is running a shell which is creating a new process group for the child process? Can anyone confirm this?)
% perl
local $SIG{INT} = sub { print "caught signal\n"; };
system('sleep', '10');
Then hit ctrl+d then ctrl+c immediately and notice that "caught signal" is never printed.
I feel like this is a simple thing... anyway to work around this? The problem is that when running a bunch of commands via system results in holding ctrl+c until all iterations are completed (because perl never gets the SIGINT) and is rather annoying...
How can this be worked around? (I already tested using fork() directly and understand that this works... this is not an acceptable solution at this time)
UPDATE: please note, this has nothing to do with "sleeping", only the fact that the command takes some arbitrary long amount of time to run which is considerably more than that of the perl around it. So much so that pressing ctrl+c gets sent to the command (as its in the foreground process group?) and somehow manages to never be sent to perl.
from perldoc system:
Since SIGINT and SIGQUIT are ignored during the execution of system,
if you expect your program to terminate on receipt of these signals you will need to arrange to do so yourself based on the return value.
#args = ("command", "arg1", "arg2");
system(#args) == 0
or die "system #args failed: $?"
If you'd like to manually inspect system's failure, you can check all possible failure
modes by inspecting $? like this:
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
Alternatively, you may inspect the value of ${^CHILD_ERROR_NATIVE} with the W*() calls from the POSIX module
I don't quite get what you're trying to achieve here... but have you tried simply comparing to:
perl -wle'local $SIG{INT} = sub { print "caught signal"; }; sleep 10;'
Can you explain what effect you're trying to go for, and why you are invoking the shell? Can you simply call into the external program directly without involving the shell?

Resources