Как написать функцию тайм-аута для цикла until в Makefile

#bash #makefile

#bash #makefile

Вопрос:

У меня есть следующий Makefile

 ready:
    until docker-compose logs some_svc | grep "ready"; do echo -n .; sleep 1; done
  

Я хочу обернуть ее функцией тайм-аута.

 define check_timeout
    timer=0
    $(1); do
        ((timer  ));
        if [[ "$$timer" == 60 ]]; then
            exit -1
        fi
        sleep 1
    done
endef

ready:
    $(call check_timeout, until docker-compose logs some_svc | grep "ready")
  

Но я получил следующую ошибку:

 $ make ready
timer=0
until docker-compose logs some_svc | grep "ready."; do
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [ready] Error 2
  

Есть идеи?

Ответ №1:

У вас есть несколько проблем.

Первый заключается в том, что make всегда использует /bin/sh для запуска рецептов. Не имеет значения, является ли ваша личная интерактивная оболочка bash, zsh или csh, она всегда будет использоваться /bin/sh . Во многих системах /bin/sh это не bash, а базовая оболочка POSIX dash . Многие элементы вашего скрипта не являются допустимыми сценариями оболочки POSIX. Поэтому, если вы хотите быть переносимым (например, для систем на базе Debian / Ubuntu), вы не можете полагаться на эти bash-измы в вашем makefile.

Либо это, либо вы должны конкретно указать make, что вы хотите bash, с:

 SHELL := /bin/bash
  

Конечно, это приведет к сбою в любой системе, которая вообще не устанавливает bash.

Во-вторых, то, что вы помещаете скрипт в define блок, не освобождает вас от необходимости использовать обратную косую черту, если вы хотите, чтобы рецепт находился в одной логической строке и передавался в один вызов оболочки. Вам нужны точки с запятой между командами (например, между exit -1 и fi и т. Д.), И вам нужны обратные косые черты в концах строк.

Это должно сработать:

 define check_timeout
    timer=0; 
    $(1); do 
    timer=$$(expr $$timer   1); 
    if [ "$$timer" = 60 ]; then 
        exit -1; 
    fi; 
    sleep 1; 
    done
endef

ready:
        $(call check_timeout, until echo ready | grep "ready")
  

Ответ №2:

В вашей карьере вы столкнетесь с бесконечными проблемами с Makefile. Многие из них можно решить, задав себе вопрос:

Должно ли это быть в Makefile, или мне было бы проще поместить эту функциональность в скрипт bash и просто вызвать этот скрипт из моего Makefile?

Чтобы улучшить читаемость ваших Make-файлов и упростить вашу жизнь, поместите эту функциональность в скрипт bash и вызовите его из вашего Makefile.

Makefile

В Makefile мы используем timeout команду, чтобы установить ограничение по времени для скрипта, который мы хотим вызвать. Мы также обрабатываем ошибку, используя оператор in case of error || .

 ready:
    timeout 60 bash until_docker.sh || exit -1
  

until_docker.sh

В скрипте bash мы реализовали функциональность, которую хотим вызвать

 until docker-compose logs some_svc | grep "ready"; do echo -n .; sleep 1;
  

Комментарии:

1. Это скорее комментарий, чем ответ.