Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

var = read foo && echo foo doesn't work #376

Closed
casey opened this issue Nov 22, 2018 · 4 comments · Fixed by #409
Closed

var = read foo && echo foo doesn't work #376

casey opened this issue Nov 22, 2018 · 4 comments · Fixed by #409
Labels

Comments

@casey
Copy link
Owner

casey commented Nov 22, 2018

In #374, @slisznia wanted a way to read a password from a user into an env variable. Unfortunately, for some strange reason, the following doesn't work:

var = `read foo && echo foo`

The following works, and I'm not sure what just is doing differently when it runs backtick commands:

use std::process::Command;

fn main() {
    let mut cmd = Command::new("sh");

    cmd.arg("-cu").arg("read foo && echo $foo");

    cmd.status().unwrap();
}

I'm not sure why this is the case. I won't have time to dig into this for the near future, so if someone wants to take a crack at it they are most welcome!

@casey
Copy link
Owner Author

casey commented Apr 16, 2019

I finally looked into this and figured out why it's happening. Backticks are evaluated with std::process::Command::output, which doesn't pass along stdin.

This can be overridden, so this can be fixed.

The potential downsides of fixing it are:

  • Stdin would then be a shared resources between backticks, which don't execute in a defined order. If multiple backticks try to read from stdin, the order in which they do so will not be defined
  • If backticks potentially read from stdin, they cannot be parallelized, when otherwise they might be
  • It will be possible to inadvertently hang just by doing things like x = `cat`

On the whole, I think these downsides are minor, so I'm leaning towards piping stdin to backtick expressions.

@casey casey added this to the soon milestone Apr 16, 2019
@runeimp
Copy link

runeimp commented Apr 18, 2019

When you say stdin would be a shared resource do you mean something like the following could happen?

test:
	echo "I'm a file!" > file.txt
	`cat file.txt | tr b x`
	`echo "Bob"`

might output

BoxI'm a file!

Like a piping or more along the lines of

$ just test < echo "Robert!"
Roxert!I'm a file!
Bob

Either possibility sounds very bad to me at the moment. I'd rather see a new function (like exec() maybe) that allows for stdin to pass through it. But maybe I'm overthinking it. Pretty tired. 😐

@casey
Copy link
Owner Author

casey commented Apr 18, 2019

This change doesn't affect the way that justfile recipe lines inherit the standard input stream, so the behavior and output of recipe commands won't change. Also, the cat command only reads from its standard input if it isn't passed any arguments, or if one of its arguments is -, so given:

test:
	echo "I'm a file!" > file.txt
	cat file.txt | tr b x
	echo "Bob"

You would always get:

$ just test < echo "Robert!"
I'm a file!
Bob

In general, most commands only read from stdin if you don't give them any arguments, so this shouldn't break any existing, working justfiles.

What I meant by stdin becoming a shared resource is that multiple backticks in a justfile will execute in some order, and just doesn't guarantee the order that backticks execute in. So if you have, for example:

x := `read foo && echo $foo`
y := `read foo && echo $foo`

default:
  echo {{x}}
  echo {{y}}

and you do:

$ printf '0\n1\n' | just

It's undefined if you'll get:

$ printf '0\n1\n' | just
0
1

Or:

$ printf '0\n1\n' | just
1
0

Note that recipe execution order is deterministic and will not change. Recipes execute in the order they are given on the command line, modulo dependencies between them, which are straightforward. But backticks in expressions may execute in any order. But they will execute in some order and not in parallel.

So if you want to read two values into just variables, you could do:

password := `printf "Enter Password: " && read p && echo $p`
username := `printf "Enter Username: " && read u && echo $u`

default:
  echo Password: {{password}}
  echo Username: {{username}}

I think this is reasonable behavior that won't do anything unexpected or broken, but definitely let me know if I've missed something.

@casey
Copy link
Owner Author

casey commented Apr 18, 2019

Also, this only affects backticks in just expressions. Backticks in recipe lines are still executed by the shell, so the behavior won't change at all there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants