Search code examples
bashmakefiledash-shell

Makefile multiline dash command run executable in a detached process


I have the following target in my makefile: (I'd like to run python http server in a detached process and when bash script is done kill the server)

TEST_PORT = 17777
test::
    $(ENV_VARS) \
    python -m SimpleHTTPServer $(TEST_PORT); \
    PID=$$(lsof -t -i @localhost:$(TEST_PORT) -sTCP:listen); \
    echo $(PID); \
    if [ -n "$$PID" ]; \
    then \
        python test.py; \
    fi; \
    function finish { \
        if [ -n "$$PID" ]; \
        then \
            kill -9 $$PID; \
        fi \
    } \
    trap finish EXIT;

However when I put a & after the line python ... I get an error

/bin/dash: Syntax error: ";" unexpected

How can this be done in a proper way?

EDIT

I have changed my makefile to do the following:

test::
    python -m SimpleHTTPServer $(TEST_PORT) &
    PID=$$(lsof -t -i @localhost:$(TEST_PORT) -sTCP:listen); \
        if [ -n "$$PID" ]; \
        then \
            $(ENV_VARS) python test.py; \
        fi \
        function finish { \
            if [ -n "$$PID" ]; \
            then \
                kill -9 $$PID; \
            fi \
        } \
        echo $$PID; \
        trap finish EXIT;

However I am getting an error: (without the line number)

/bin/dash: Syntax error: word unexpected


Solution

  • The important thing to remember here is that your line breaks don't actually exist when the shell sees the command.

    So your first command becomes:

    $(ENV_VARS) python -m SimpleHTTPServer $(TEST_PORT); PID=$$(lsof -t -i @localhost:$(TEST_PORT) -sTCP:listen); echo $(PID); if [ -n "$$PID" ]; then python test.py; fi; function finish { if [ -n "$$PID" ]; then kill -9 $$PID; fi } trap finish EXIT;
    

    And your second command becomes:

    PID=$$(lsof -t -i @localhost:$(TEST_PORT) -sTCP:listen); if [ -n "$$PID" ]; then $(ENV_VARS) python test.py; fi function finish { if [ -n "$$PID" ]; then kill -9 $$PID; fi } echo $$PID; trap finish EXIT;
    

    Now those are both very hard to read so I don't expect you to spot the problem but the problem is that you are missing statement terminators in a few places.

    Specifically:

    • Braces ({}) are word elements and so need spaces around them (and a terminator before, and after, the closing brace). You are missing those terminators here fi } trap and here fi } echo.

    • fi is also not a statement terminator and so it needs one between it and the next statement. You are missing one here test.py; fi function (as well as the ones in the braces from the first point).