Преобразовать Makefile / список Bash в список Python

#python #makefile

#python #makefile

Вопрос:

С помощью следующего файла Makefile:

 datetime := $(shell date  %Y%m%d%H%M%S)
    
target := $(shell echo $$TARGET)

dothis:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns('1', '2', '3')); 
                "
        
dothat:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns('1', '2', '3')); 
                print('done')"
  

Я могу

 $ TARGET=folder1 make dothis
  

и

 $ TARGET=folder2 make dothat
  

Где dothis выполняется скрипт Pyhton и dothat выполняется другой скрипт Python, $target приходит из командной строки и заменяется в скрипте Python.

В обоих случаях я передаю список ignore_patterns , поскольку список для dothis одинаков, и dothat я думаю определить его только один раз в Makefile и передать его в скрипте Python в качестве переменной, как я делаю для datetime .

Как я могу преобразовать список Bash / Makefile в список Python?

Я попробовал следующее, хотя это не работает.

 datetime := $(shell date  %Y%m%d%H%M%S)
    
target := $(shell echo $$TARGET)
                
list := $(1 2 3)

dothis:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(list))); 
                "
        
dothat:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(list))); 
                print('done')"
  

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

1. Вы пробовали sys.argv и передавали список в качестве аргументов скрипту?

2. На самом деле я хотел бы, чтобы список в скрипте не передавался

Ответ №1:

make не содержит списков или даже чисел. В нем просто есть строки. Но этого должно быть достаточно для ваших целей.

Однако, прежде чем мы перейдем к этому, несколько комментариев к вашему примеру кода:

  • если ваша единственная цель установки TARGET переменной окружения — иметь возможность передавать ее значение в target макрос makefile, тогда вы черпаете вдохновение у Рубе Голдберга. Вы можете задавать make макросы непосредственно в командной строке — назначения просто должны отображаться в качестве аргументов для make :

      make target=folder1 dothis
      

    или

      make dothat target=folder2
      
  • В makefile $() синтаксис запрашивает расширение макроса или (только GNU make) вызова функции. $(1 2 3) не выражает ни того, ни другого, потому что 1 2 3 это недопустимое имя переменной и 1 это не имя какой-либо встроенной функции. Вам не нужны специальные разделители вокруг буквенного текста make значения макроса.

  • Вам не нужен или особенно нужен список Python для аргумента shutil.ignore_patterns() . Все, что вам нужно, это последовательность аргументов, разделенных запятыми. Если вы планируете представлять globs, вам нужно будет указать соответствующие цитаты на Python, но для make вам не нужны никакие специальные цитаты.

  • Если у вас есть правило make, рецепт которого на самом деле не создает целевой объект (в виде файла), то обычно неплохо предупредить make об этом, обозначив целевые объекты таких правил как предварительные условия специального целевого объекта .PHONY . Это GNU-изм, но он должен быть безвреден для make тех, кто его не понимает, и вы все равно уже полагаетесь на функции, специфичные для GNU.

Что-то вроде этого должно сработать:

 datetime := $(shell date  %Y%m%d%H%M%S)

# Default to the current working directory; can be overridden on the command line:
target := .

# The arguments to to shutil.ignore_patterns, which are text to `make`:
ignore := 1, 2, 3

dothis:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(ignore)))"
        
dothat:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(ignore))); 
                print('done')"

.PHONY: dothis dothat
  

ОДНАКО в данном конкретном случае я бы пошел дальше. Ваши два скрипта на Python идентичны, за исключением того, включают ли они print('done') инструкцию. Зачем все это повторять? Есть несколько способов избежать повторения, но это один из самых простых:

 datetime := $(shell date  %Y%m%d%H%M%S)

# Default to the current working directory; can be overridden on the command line:
target := .

# The arguments to to shutil.ignore_patterns, which are text to `make`:
ignore := 1, 2, 3

dothis:
    @python -c "import shutil ; 
                from shutil import copytree, ignore_patterns; 
                shutil.copytree('$(target)', 'target-$(datetime)', ignore=ignore_patterns($(ignore)))"

# First, build target dothis, then print "done":
dothat: dothis
    echo done

.PHONY: dothis dothat
  

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

1. Почему вы вызываете target макрос? Могу ли я назвать это переменной?

2. @KcFnMi, «макрос» — это терминология, используемая POSIX. «Переменная» является часто используемой альтернативой. Вы можете использовать любой из них, но данный случай на самом деле показателен, если вместо этого вы посмотрите на ignore макрос / переменную. Расширение до 1, 2, 3 , как я уже предлагал, того, что является фрагментом более крупного выражения на другом языке, скорее более похоже на макросы и скорее менее похоже на переменные, по крайней мере, для меня.