Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get `make` to prompt the user for a password and store it in a Makefile variable?

Tags:

I'm writing a Makefile, and some of the commands the makefile runs require a password. I'd like to give the user the ability to either pass this in as a Makefile variable using make PASSWORD=password or if the user does not pass it in, then prompt the user for it and store their response in said Makefile variable.

At the moment, I'm able to check the Makefile variable, and then as part of my target specific rules, write shell commands that prompt the user for the password and store it in a shell variable. However, this variable is only available to that specific shell and not any others.

How do I read something from the user and store it in a variable?

I've tried the following:

PASSWORD ?= $(shell read -s -p "Password: " pwd; echo $pwd) 

but the prompt is never printed. I've also tried echo "Password: " inside shell, but that isn't printed either.

Any ideas?

Edit:

To clarify, the password needs to be set for a specific target, so I have something like this:

PASSWORD :=   my-target: PASSWORD ?= $(shell read -s -p "Password: " pwd; echo $$pwd)  my-target:     # rules for mytarget that use $(PASSWORD) 

Edit 2:

I found the problem. When I set PASSWORD := at the top of the script, it sets PASSWORD to an empty string, and this in turn causes the ?= to be skipped (since PASSWORD) is already set.

like image 489
bluesmoon Avatar asked Dec 19 '13 00:12

bluesmoon


People also ask

How do you take user input in Makefile?

If you want to get user input from within a Makefile, ensure you run the read command in one line. It turns out that each line is run in its own subshell. So if you read in user input, ensure you have semicolons and backslashes to ensure commands are run in the same subshell.


2 Answers

A couple of things:

  • the $ for dereferencing shell variable pwd is being interpreted by make. You can escape it from make with $$
  • make is invoking the shell as Posix compatible /bin/sh instead of /bin/bash. As such, the -s option to read is not supported.

Try this instead:

PASSWORD ?= $(shell bash -c 'read -s -p "Password: " pwd; echo $$pwd') 

This worked for me on Ubuntu 12.04 / GNU make 3.81 / bash 4.2.25(1)

And on OSX 10.8.5 / make 3.81 / bash 3.2.48(1):

 $ cat Makefile  PASSWORD ?= $(shell bash -c 'read -s -p "Password: " pwd; echo $$pwd')  all:     echo The password is $(PASSWORD) $ make Password: echo The password is 1234 The password is 1234 $  

Update - @user5321531 pointed out that we can use POSIX sh instead of bash, and temporarily suppress echo with stty:

PASSWORD ?= $(shell stty -echo; read -p "Password: " pwd; stty echo; echo $$pwd) 
like image 66
Digital Trauma Avatar answered Oct 31 '22 23:10

Digital Trauma


To answer @joeb 's question:

$ make; echo "---Makefile---"; cat Makefile Password: <hidden> test test ---Makefile--- all: first second PASSWORD ?= $(shell read -s -p "Password: " pass; echo $$pass) define formatted first:         @echo $1 second:         @echo $1 endef  $(eval $(call formatted,$(PASSWORD))) 
like image 34
Brian Hannay Avatar answered Oct 31 '22 23:10

Brian Hannay