Iulian Onofrei
Iulian Onofrei

Reputation: 9740

Execute command in Makefile only if shell command output is empty

I'm trying to run some commands only if a shell command output is empty, like this:

setup-database:
    database=$(shell docker-compose exec mariadb mysql -e "select schema_name from information_schema.schemata where schema_name = 'dbname'" --silent --silent)

ifeq ($(strip $(database)),)
    docker-compose exec mariadb mysql -e "create database dbname"

    # ...
endif

but it doesn't work. It executes the commands inside the if, regardless the first command's output.

Upvotes: 0

Views: 837

Answers (2)

Beta
Beta

Reputation: 99144

The problem is that you're mixing Make commands and shell commands.

setup-database:
    database=$(shell docker-compose some things)
ifeq ($(strip $(database)),)
    docker-compose some other things
    # ...
endif

That ifeq ... endif is a Make conditional. Make will evaluate it before running any rule; the variable database is empty to begin with, so Make always includes that block of rules in the recipe. (And in fact the make variable database remains empty. The database that gets assigned a value is a shell variable.

Since you want to test the variable when the rule is executed, it should be a shell variable, tested with a shell conditional. On the command line, this would be:

database=`docker-compose some things`
if [ -z $database ]
  then
  docker-compose some other things
  ...
fi

(I don't think [ -z STRING ] cares about whitespace, so we don't need $(strip ...).)

Since every command in a recipe runs in a separate subshell, the whole thing must be on one line or the value of the variable will be lost:

database=`docker-compose some things`; if [ -z $database ] ; then docker-compose some other things; ...; fi

And when we put this in a makefile, we use $(shell ...) instead of backticks, and escape the $ (and optionally use some backslashes to make the rule more readable):

setup-database:
    database=$(shell docker-compose some things);\
  if [ -z $$database ] ; then \
  docker-compose some other things; \
  ... \
  fi

Upvotes: 1

dash-o
dash-o

Reputation: 14493

Make does not provide direct option to extract values of specific operation into variables. Two options to consider: - using a make symbol, tracking the result a file.

  1. create make symbol
  # Note: nothing get executed.
db_check=$(shell docker-compose exec mariadb mysql -e "select schema_name from information_schema.schemata where schema_name = 'dbname'" --silent --silent)

In setup-database:
    # Create shell variable. Useful only on the same line.
    database="${db_check}" ; [ "$database" ] || docker-compose exec mariadb mysql -e "create database dbname"

    # ...

Upvotes: 0

Related Questions