使用 make 编写 Bash 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16112066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:13:32  来源:igfitidea点击:

Bash scripting with make

bashmakefile

提问by user2300448

I have a makefile which I use to run simple bash scripts inside of a repo I am working on. I am attempting to make a new make call which will log me into my mySQL database automatically. I have my username and password stored in a .zinfo file at a known location (such as "/u/r/z/myid/.zinfo"). I am attempting to read the lines of this file to get my password, which is of the format:

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

user = csj483
database = cs495z_csj483
password = fjlID9dD923

Here is the code I am trying to run from the makefile, but it is not working. If I run the same code directly in the shell, it seems to work ok. Note that I had to use double $$s because make doesn't like single ones.

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

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

At this point, I am just trying to get the password, which should be the last value that PASSWORD is set to in the loop. If anyone can suggest an easier way to retrieve the password, or point out my error in my code, I would appreciate it. Eventually I will also want to retrieve the database name as well, and any help with that too would be appreciated as well. I am new to bash, but experienced in numerous other languages.

此时,我只是想获取密码,它应该是 PASSWORD 在循环中设置的最后一个值。如果有人可以建议一种更简单的方法来检索密码,或者指出我的代码中的错误,我将不胜感激。最终,我还想检索数据库名称,也将不胜感激。我是 bash 的新手,但对许多其他语言有经验。

回答by MadScientist

You didn't specify what you meant by "not working"; when asking questions please always be very clear about the command you typed, the result you got (cut and paste is best), and why that's not what you expected.

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

Anyway, most likely the behavior you're seeing is that the first echo shows the output you expect, but the second doesn't. That's because makewill invoke each logical line in the recipe in a separate shell. So, the for loop is run in one shell and it sets the environment variable PASSWORD, then that shell exits and the last echois run in a new shell... where PASSWORDis no longer set.

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

You need to put the entirety of the command line in a single logical line in the recipe:

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

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

One last thing to remember: you say you're running bash scripts, but make does notrun bash. It runs /bin/sh, regardless of what shell you personally use (imagine the havoc if makefiles used whatever shell the user happened to be using!). Your best option is to write recipes in portable shell syntax. If you really can't do that, be sure to set SHELL := /bin/bashin your Makefileto force make to use bash.

最后一两件事要记住:你说你正在运行的bash脚本,但要它运行bash的。/bin/sh无论您个人使用什么 shell,它都会运行(想象一下,如果 makefile 使用用户碰巧使用的任何 shell,将会造成严重破坏!)。最好的选择是用可移植的 shell 语法编写配方。如果你真的不能这样做,一定要SHELL := /bin/bash在你Makefile的强制 make 中设置使用 bash。

ETA:

预计到达时间:

Regarding your larger question, you have a lot of options. If you have control over the format of the zinfo file at all, then I urge you to define it to use the same syntax as the shell for defining variables. In the example above if you removed the whitespace around the =sign, like this:

关于你更大的问题,你有很多选择。如果您完全可以控制 zinfo 文件的格式,那么我强烈建议您将其定义为使用与 shell 相同的语法来定义变量。在上面的示例中,如果您删除了=标志周围的空格,如下所示:

user=csj483
database=cs495z_csj483
password=fjlID9dD923

Then you have a valid shell script with variable assignments. Now you can source this script in your makefile and your life is VERY easy:

然后你就有了一个带有变量赋值的有效 shell 脚本。现在你可以在你的 makefile 中获取这个脚本,你的生活非常简单:

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

If you don't have control over the syntax of the zinfo file then life is harder. You could use eval, something like this:

如果您无法控制 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

This version will only work if there ARE spaces around the "=". If you want to support both that's do-able as well.

此版本仅在“=”周围有空格时才有效。如果您想同时支持两者,那也是可行的。