7

The following sequence gives me the return value of the first command, not the 2nd as I would have expected (no matter if I run the 1st command in a subshell):

sudo systemctl start x; sudo systemctl is-active --quiet x; echo $?;
(sudo systemctl start x); sudo systemctl is-active --quiet x; echo $?;

The service x is broken and could not be started - so he's not running. The following command, ran stand-alone, gives me a correct return value of 3 as it should be:

sudo systemctl is-active --quiet x; echo $?;

So, why am I getting the return value of the first command (0) when running command; command; echo $? instead of the return value (3) of the second with echo $??

I'm on GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu). I know, that if I split it on 2 lines, it works:

sudo systemctl start x;
sudo systemctl is-active --quiet x; echo $?;

But I need to have it as a one-liner, as I'm putting it in PHP shell_exec() function. And running twice shell_exec() has the same result as putting the commands in one line.

13

When I encounter an issue like this, I tend to follow Sherlock Holmes’ mantra, and consider what is left, however implausible, once the impossible is eliminated. Of course with computers nothing is impossible, however some things are so unlikely we can ignore them at first. (This makes more sense with the original title, “command; command; echo $? — return value is not correct, why?”)

In this case, if

sudo systemctl start x; sudo systemctl is-active --quiet x; echo $?;

shows that $? is 0, that means that systemctl is-active really did indicate success. The fact that a separate systemctl is-active shows that the service isn’t active strongly suggests that there’s a race between the service and the human operator typing the commands; basically, that the service does start, to a sufficient extent for systemctl start to finish, and systemctl is-active to run and find the service active, but then the service fails, so a human-entered systemctl is-active finds it inactive.

Adding a short delay between systemctl start and systemctl is-active should avoid the false positive.

3

Systemd brings the service up for a short time (0.1 seconds) and then the service crashes.

Returns 3 as it should be;

sudo systemctl start x; sleep 0.2; sudo systemctl is-active --quiet x; echo $?;

Less, than 0.2 seconds, it returns 0 as it should not be:

sudo systemctl start x; sleep 0.1; sudo systemctl is-active --quiet x; echo $?;

Also if I do systemctl start x; ps -fA | grep -i x I see the service. If I run ps again after that, it's gone.

  • 1
    An ExecStartPost that checks whether the service is really up and fails if it isn't is one way to avoid this. If you maintain the source to your service and use the sd_notify socket to self-report startup success, even moreso. Which is to say -- it's entirely possible to make sure systemd knows when a service is in fact successfully initialized; it just takes some extra code. – Charles Duffy Apr 27 '18 at 15:51
  • +1 @CharlesDuffy for sd_notify information - unfortunately I do not maintain the source files. That's why it's easier to use sleep and wait to see what happens :) – chevallier Apr 27 '18 at 18:41
1

Try this:

sudo systemctl start x && sudo systemctl is-active --quiet x; echo $?;

The && will force the system to run the commands in order, and only if the previous command completed successfully.

  • 2
    This does not handle the case which the user is most likely experiencing here, which is that the service does start, for long enough for the is-active to return true as well, but then dies. As others have suggested, it would be better to insert a short delay of a a second or two between the two systemctl calls. – Kusalananda Feb 12 at 17:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.