Home > front end >  Exist code handling in multi-line shell commands
Exist code handling in multi-line shell commands

Time:09-30

I have a multi-line shell command in a Makefile:

format:
    . $(venv_activate_path) ;\
    echo "           ISORT           " ;\
    isort -rc . ;\
    echo $? ;\
    echo "    isort status " ;\
    echo "           BLACK           " ;\
    black $(package_name)/ --check ;\
    echo $? ;\
    echo "    black package status " ;\
    black tests/ --check ;\
    echo $? ;\
    echo "    black test status "

I want this whole thing to return non-zero exist status if either of these scripts has exit code 1. Nonetheless, I want to run all commands, regardless of whether the first fails as I call this on github actions.

The echo $? are all empty despite the processes (black and isort) returning exit code 1 when run individually and the echo $? of the entire make format command is 0. How do I get the make format command to return exit code 1 if at least one of these scripts has non-zero exit code?

CodePudding user response:

You can run both in the background and then wait.

This is pretty ugly as a make target; perhaps refactor it to a separate script.

format:
    . $(venv_activate_path);\
    isort -rc . & isort=$$!; \
    black $(package_name)/ --check & black=$$!; \
    wait $$isort; isortresult=$$?; \
    wait $$black; blackresult=$$?; \
    exit $$((isortresult blackresult))

If these commands are rewriting the files, you will need some additional checks to force them to wait for each other. Ultimately, perhaps a better solution will be to run each separately.

(Stack Overflow renders tabs as spaces, so you will not be able to copy/paste this recipe directly.)

CodePudding user response:

Supposing that your condition "if either of these scripts has exit code 1" can be interpreted as "if any of these commands exit with nonzero status", this is is a fairly clean and clear solution:

format:
    . $(venv_activate_path) ;\
    failed=0;\
    isort -rc . || failed=1;\
    black $(package_name)/ --check || failed=1;\
    black tests/ --check || failed=1;\
    test "$failed" -eq 0

It runs the commands sequentially, using variable failed to track whether any command fails. At the end, it uses the test command to exit with status 0 if $failed still has the value 0, or with a failure status otherwise. You can restore some or all of the echo commands if you like, other than after the test command, which must be last. However, you still will not get useful information from the $? variable to feed to them.

  • Related