команда `read` не работает в Makefile

У меня есть скрипт make для выполнения 3 задач:

  1. Импортировать базу данных MySQL
  2. Переместить файл конфигурации
  3. Настроить конфигурационный файл

Для этих задач сценарий требует 3 ввода:

  1. MySQL Host
  2. Имя пользователя MySQL
  3. Пароль MySQL

По какой-то причине всякий раз, когда я read ввод, он сохраняет правильную переменную, но содержимое – это имя переменной, которое я сохраняю без первой буквы. Я не могу понять, почему это так.

Вот Makefile :

 SHELL := /bin/bash default: @echo "Welcome!";\ echo -n "Please enter the MySQL host (default: localhost):";\ read host;\ host=${host:-localhost};\ echo -n "Please enter the MySQL username:";\ read username;\ echo -n "Please enter the MySQL password:";\ read -s password;\ mv includes/config.php.example includes/config.php 2>/dev/null;true;\ sed 's/"USER", ""/"USER", "$(username)"/g' includes/config.php > includes/config.php;\ sed 's/"PASSWORD", ""/"PASSWORD", "$(password)"/g' includes/config.php > includes/conf$ echo $username;\ echo $password;\ mysql -u "$username" -p"$password" codeday-team < ./codeday-team.sql;\ echo "Configuration complete. For further configuration options, check the config file$ exit 0; 

Выход:

 Welcome! Please enter the MySQL host (default: localhost): Please enter the MySQL username:<snip> Please enter the MySQL password:sername assword ERROR 1045 (28000): Access denied for user 'sername'@'localhost' (using password: YES) Configuration complete. For further configuration options, check the config file includes/config.php 

Как вы можете видеть, он выводит sername и assword . Для жизни меня я не могу это исправить!

Хотя цель этого сообщения – решить проблему read , я был бы признателен за любые советы, отчеты об ошибках или предложения. Я могу присудить им награду.

Спасибо за помощь!

Вы смешиваете оболочку и make переменные там. Оба make и оболочка используют $ для своих переменных.

В Makefile переменными являются $(var) или $v для однобуквенных переменных и $var или ${var} в оболочках.

Но если вы напишете $var в Makefile, make поймет его как $(v)ar . Если вы хотите передать литерал $ в оболочку, вам нужно ввести его как $$ , как в $$var или $${var} чтобы он стал $var или ${var} для оболочки.

Кроме того, make run sh , а не bash для интерпретации этого кода ( Edit , sorry пропустил ваш SHELL := /bin/bash выше, обратите внимание, что во многих системах нет bash в /bin если у них вообще есть bash и := is GNU ), поэтому вам нужно использовать синтаксис sh . echo -n , read -s – синтаксис zsh / bash , а не синтаксис sh .

Лучше всего было бы добавить скрипт zsh / bash для этого (и добавить зависимость сборки от bash ). Что-то вроде:

 #! /usr/bin/env bash printf 'Welcome\nPlease enter the MySQL host (default: localhost): ' read host || exit host=${host:-localhost} printf "Please enter the MySQL username: " read username || exit printf "Please enter the MySQL password:" IFS= read -rs password || exit printf '\n' mv includes/config.php.example includes/config.php 2>/dev/null repl=${password//\\/\\\\} repl=${repl//&/\\&} repl=${repl//:/\\:} { rm includes/config.php && sed 's/"USER", ""/"USER", "'"$username"'"/g s:"PASSWORD", "":"PASSWORD", "'"$repl"'"/g' > includes/config.php } < includes/config.php || exit mysql -u "$username" -p"$password" codeday-team < ./codeday-team.sql || exit echo "Configuration complete. For further configuration options, check the config file" 

В нем рассматриваются еще несколько вопросов:

  • вам нужно -r при чтении пароля, если вы хотите разрешить пользователю использовать обратную косую черту в своем пароле.
  • вам нужно IFS= если вы хотите разрешить пользователю вводить пароль, который начинается или заканчивается пробелами
  • то же самое относится и к имени пользователя, но здесь мы делаем предположение, что пользователь не будет использовать что-либо глупое для имени пользователя, а обработка пустой дескрипции и обратной косой черты может рассматриваться как / feature /.
  • ваш ;true после того, как mv не делает то, что вы думаете, что он делает. Он не отменяет эффект параметра errexit (для make реализации, вызывающего оболочку с -e ). Вместо этого вам понадобится ||true . Здесь мы не используем errexit но делаем ошибку, обрабатывая себя с || exit || exit туда, где это необходимо.
  • Вам нужно избегать обратной косой черты, & и s:pattern:repl: separator (здесь s:pattern:repl: или он не будет работать (и может иметь неприятные побочные эффекты).
  • Вы не можете сделать sed ... < file > file , так как file будет усечен до того, как sed будет запущен. Некоторые реализации sed поддерживают опцию -i или -i '' . В качестве альтернативы вы можете использовать perl -pi . Здесь мы делаем эквивалент perl -pi вручную (удаляем и воссоздаем входной файл после того, как он открыт для чтения), но не заботясь о метаданных файла.

    Здесь было бы лучше использовать пример один как входной, а последний – как вывод.

Он по-прежнему не затрагивает еще несколько вопросов:

  • новый config.php создается с разрешениями, полученными из текущего umask который, вероятно, будет umask для чтения в мире и принадлежит пользователю, выполняющему make . Возможно, вам придется адаптировать umask и / или изменить право собственности, если includes dir не ограничивается иначе, поскольку этот файл содержит конфиденциальную информацию.
  • если пароль содержит " символы», которые, вероятно, будут ломаться (на этот раз для php ). Вы хотите либо запретить их (возвращая ошибку), либо добавить для них еще один уровень экранирования в правильном синтаксисе для этого php файла. вероятно, будут иметь схожие проблемы с обратным слэшем, и вы можете также исключить не-ascii или контрольные символы.
  • Передача пароля в командной строке mysql – это, как правило, плохая идея, так как это означает, что она выводится на выходе ps -f . Лучше использовать:

      mysql --defaults-file=<( printf '[client]\nuser=%s\npassword="%s"\n' "$username" "$password") ... 

    printf будет встроен, он не будет отображаться в выпуске ps .

  • переменная $host не используется.

  • запрос такого пользователя означает, что ваш скрипт не может быть легко автоматизирован. Вместо этого вы можете ввести данные из аргументов или (лучше для пароля) с переменными окружения.

вы не используете никаких функций Makefile, пытаетесь ли вы писать эти строки в одной оболочке?

следующий в Makefile, который вы используете

  echo $username;\ echo $password;\ 

make будет анализировать $username как $u (пустая переменная) + sername (строка)

попробуйте заменить $username на $$username если вы хотите остаться в Makefile.