使用make进行Bash脚本编写

4

我有一个makefile,用于在我正在工作的存储库中运行简单的bash脚本。我试图创建一个新的make调用,它将自动登录到我的MySQL数据库。我已经将用户名和密码存储在已知位置(例如“/u/r/z/myid/.zinfo”)的.zinfo文件中。我试图读取此文件的行以获取我的密码,其格式为:

user = csj483
database = cs495z_csj483
password = fjlID9dD923

这是我尝试从Makefile运行的代码,但它不起作用。如果我直接在shell中运行相同的代码,似乎可以正常工作。请注意,我必须使用双$$,因为make不喜欢单个$。

login:
    for line in $$(cat /u/z/users/cs327e/$$USER/.zinfo); \
    do \
        PASSWORD=$$line; \
        echo $$PASSWORD; \
    done 
    echo $$PASSWORD

目前,我只想获取密码,这应该是在循环中设置PASSWORD的最后一个值。如果有人能建议更简单的方法来检索密码,或指出我代码中的错误,我将不胜感激。最终,我还想检索数据库名称,对于这方面的任何帮助也将不胜感激。我新手学习bash,但在许多其他编程语言方面有丰富的经验。

1个回答

14

你没有说明“不起作用”指的是什么;在提问时,请始终非常清楚地说明您输入的命令、您得到的结果(最好是剪切并粘贴),以及为什么这不是您所期望的。

无论如何,最可能出现的情况是,您看到的行为是第一个echo显示了您期望的输出,但第二个echo没有。那是因为make将在配方中的每个逻辑行中调用一个单独的shell。所以,for循环在一个shell中运行并设置环境变量PASSWORD,然后该shell退出,并在新shell中运行最后一个echo...在那里PASSWORD不再设置。

您需要将整个命令行放在配方的单个逻辑行中:

login:
         for line in $$(cat /u/z/users/cs327e/$$USER/.zinfo); do \
             PASSWORD=$$line; \
             echo $$PASSWORD; \
         done \
         && echo $$PASSWORD

记住一件事:你说你在运行bash脚本,但make不会运行bash。无论你个人使用什么shell(想象一下如果makefiles使用用户正在使用的任何shell会造成多大混乱!),它都会运行/bin/sh。你最好的选择是使用便携式shell语法编写配方。如果真的无法这样做,请确保在Makefile中设置SHELL:= /bin/bash以强制make使用bash。

ETA:

关于您的更大问题,您有很多选择。如果您能够控制zinfo文件的格式,则建议您定义其使用与定义变量的shell相同的语法。在上面的示例中,如果删除=符号周围的空格,则如下所示:

user=csj483
database=cs495z_csj483
password=fjlID9dD923

如果你已经有一个包含变量赋值的有效的Shell脚本,你可以在你的makefile中引用这个脚本,这样你的生活就非常简单了:

login:
        . /u/z/users/cs327e/$$USER/.zinfo \
            && echo user is $$user \
            && echo database is $$database \
            && echo password is $$password

如果您无法控制zinfo文件的语法,则生活会更加艰难。您可以使用eval,就像这样:

login:
        while read var eq value; do \
            eval $$var="$$value"; \
        done < /u/z/users/cs327e/$$USER/.zinfo \
            && echo user is $$user \
            && echo database is $$database \
            && echo password is $$password

只有在 " = " 周围有空格时,此版本才能正常工作。如果您想要同时支持两种方式,也是可行的。


非常感谢!就像我说的,我对bash(或者shell中的任何东西)和make都不太熟悉;我主要是一名Python程序员。不幸的是,我无法控制.zinfo文件;它由我的数据库课程教授维护。 - user2300448
我使用第一个建议将&&简单地添加到我的最后一行,成功使登录正常工作,但我尝试了最后一个块,并且在运行时,它只是说“没有任何要做的“login”。我在末尾添加了一个与第一个示例相同的调用mysql语句的语句。有什么想法吗? - user2300448
很难理解你的描述:如果你在问题中更新实际的makefile规则,那么它会更简单。然而,形式为“XXX无需执行任何操作”的消息意味着make认为目标“XXX”是最新的。由于你的“login”目标没有前提条件,如果该目标存在,它将被视为最新的。所以,我想说你的目录中有一个名为“login”的文件。要么删除该文件,要么更好地声明“login”目标为虚拟目标,方法是在你的makefile中添加“.PHONY: login”。 - MadScientist
在POSIX shell中编写脚本有什么好处呢?现在大多数系统都有bash,使用bash的特性可以使代码更清晰。 - Elazar Leibovich
大多数系统是相对的。在任何*BSD系统上通常都不可用,也不可用于Solaris或其他非GNU/Linux系统上。在较小的系统上通常也不可用(尽管可以承认的是,大多数系统不会运行make)。另外,使用哪个版本的bash?并非所有版本都支持所有功能,而且较旧但仍得到支持的GNU/Linux系统使用的是较旧的bash版本。最简单的方法是只使用POSIX sh。如果您编写的makefile配方足够复杂以真正发挥bash功能的优势,那么您可能应该重新考虑您的实现方式。 - MadScientist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接