`read` 命令在 Makefile 中不起作用

Aar*_*sau 5 shell make variable

我有一个 make 脚本来执行 3 个任务:

  1. 导入 MySQL 数据库
  2. 移动配置文件
  3. 配置配置文件

对于这些任务,脚本需要 3 个输入:

  1. MySQL主机
  2. 用户名
  3. 密码

出于某种原因,每当我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;
Run Code Online (Sandbox Code Playgroud)

输出是:

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
Run Code Online (Sandbox Code Playgroud)

如您所见,它输出sernameassword。对于我的生活,我无法解决这个问题!

虽然这篇文章的目的是解决read错误,但我希望得到任何建议、错误报告或建议。我可以赏金给他们。

感谢您的帮助!

Sté*_*las 6

make在那里混合了 shell 和变量。无论make和外壳使用$他们的变量。

在 Makefile 中,变量是$(var)$v用于单字母变量,和/$var${var}在外壳中。

但是如果你写$var在一个 Makefile 中,make就会把它理解为$(v)ar. 如果要将文字传递$给 shell,则需要将其输入为$$, as in $$varor$${var}以便它成为$var${var}for shell。

另外,make运行sh,不能bash解释的代码(编辑,遗憾错过了你的SHELL := /bin/bash上面,请注意,许多系统没有bash/bin他们是否有bash在所有和:=是GNU特定的),所以你需要使用sh的语法出现。echo -n,read -szsh/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"
Run Code Online (Sandbox Code Playgroud)

它解决了更多问题:

  • -r如果您想允许用户在其密码中使用反斜杠,则在读取密码时需要。
  • 你需要IFS=,如果你想允许用户有一个密码,在空格开始或结束
  • 同样适用于用户名,但在这里我们假设用户不会对用户名使用任何愚蠢的东西,并且空白剥离和反斜杠处理可以被视为 /feature/。
  • 你的;truemv不会做你认为它会做的事情。它不会取消errexit选项的效果(对于make使用 调用 shell 的实现-e)。你需要||true代替。在这里,我们不是在使用,errexit而是|| exit在需要的地方自行处理错误。
  • 您需要转义反斜杠&s:pattern:repl:分隔符(此处:),否则它将不起作用(并且可能会产生令人讨厌的副作用)。
  • 你不能做sed ... < file > file,因为filesed开始之前会被截断。一些sed实现支持一个-ior-i ''选项。或者,您可以使用perl -pi. 在这里,我们所做的相当于perl -pi手动(在输入文件打开读取后删除并重新创建它),但没有处理文件的元数据。

    在这里,最好使用示例之一作为输入,最后一个作为输出。

它仍然没有解决更多问题:

  • config.php创建的权限来自当前umask可能是世界可读的并且由运行的用户拥有makeumask如果includes目录不受其他限制,因为该文件包含敏感信息,则您可能需要调整和/或更改所有权。
  • 如果密码包含"字符,则可能会中断(这次是php)。您可能想要禁止那些(通过返回错误)或以该php文件的正确语法为它们添加另一层转义。您可能会遇到与反斜杠类似的问题,并且您可能还想排除非 ascii 或控制字符。
  • 在命令行上传递密码mysql通常是一个坏主意,因为这意味着它会显示在ps -f. 最好使用:

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

    printf是内置的,它不会出现在ps输出中。

  • $host未使用该变量。

  • 像这样提示用户意味着您的脚本无法轻松自动化。您可以使用环境变量从参数或(更好的密码)中获取输入。


Arc*_*mar 5

您没有使用 Makefile 的任何功能,您是否尝试在单个 shell 中编写这些行?

接下来在您使用的 Makefile 中

    echo $username;\
    echo $password;\
Run Code Online (Sandbox Code Playgroud)

make 将解析$username$u(空变量) + sername(字符串)

尝试更换$username$$username,如果你想留在Makefile文件。