Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash scripting with make

Tags:

bash

makefile

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:

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.

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.

like image 651
user2300448 Avatar asked Dec 08 '22 16:12

user2300448


1 Answers

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 make will 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 echo is run in a new shell... where PASSWORD is no longer set.

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 not run 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/bash in your Makefile to force make to use 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:

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:

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:

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.

like image 91
MadScientist Avatar answered Jan 02 '23 20:01

MadScientist