-1

I want to find the 2 version of python. If I write:

{python2,python3}" --version; "

I am expecting it to run:

python2 --version; python3 --version;

and provide me the versions like if I would have written the above line directly :

Python 2.7.18 
Python 3.8.10

but instead I get:

python2 --version;: command not found

even though if I test the output with:

echo {python2,python3}" --version"

I do get the expected:

python2 --version; python3 --version;

Trying

`echo {python2,python3}" --version"`

didn't work either. Why? How do I make it work?

programmer
  • 41
  • 6
  • can you provide a bit of context? what is this? part of a bash script? do you always check the same (python 2 and 3) or some others too? Why can't you run it normally instead of doing this? – Gerge Jan 23 '23 at 13:48

1 Answers1

1

Because that's not what it does. You are creating two quoted strings "python2 --version; " and "python3 --version; " neither of which is a valid command. You could get around that with eval but ... that way lies madness.

# XXX DON'T
eval python{2,3}" --version;"
2.7.18
Python 3.8.10

The (not so) simple but straightforward solution would be something like

for v in 2 3; do
    python$v --version
done

or if you are hellbent on using a wildcard, run a subshell:

echo python{2,3}" --version;" | bash

Perhaps notice the (lack of) difference between

echo python2" --version; "

and

echo "python2 --version; "

The quotes simply tell the shell to keep things together as a single string. (For what it's worth, the shell removes the quotes as part of its parsing process, so the argument to echo does not contain any actual quotes, just the parsed string from between the quotes.)

It's possible to have command names with literal spaces in them, but incredibly cumbersome; so you don't see this much in practice.

For fun, maybe try

# Have a directory in your PATH which is in your home directory
# If you don't, maybe create $HOME/bin and add it to your PATH
bash$ echo "$PATH" | tr ':' '\n' | grep "$HOME"
/users/you/bin

bash$ cat >"$HOME/bin/python2 --version"
#!/bin/sh
exec python2 --version
^D

bash$ chmod +x "$HOME/bin/python2 --version"

bash$ "python2 --version"
2.7.18

(Maybe delete the script when you're done experimenting.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • But then why does: echo {python2,python3}" --version;" | bash provides the correct answer? – programmer Jan 23 '23 at 13:59
  • It's similar to the `eval` case, except you are creating a new subprocess to run the commands. The quotes are stripped before `echo` runs, as you can easily establish experimentally. – tripleee Jan 23 '23 at 14:00
  • But when you pipe you simply pushing the string "python2 --version; python3 --version" and therefore that should be similar to: bash "python2 --version; python3 --version" , but that does not work! – programmer Jan 23 '23 at 14:02
  • Because the argument to `bash` should be a file name. Try `bash -c "python2 --version; python3 --version;"`. Updated the answer to include this variant. – tripleee Jan 23 '23 at 14:03
  • Actually: bash -c python{2,3}" --version;" does not work! It only gives the version of python2! – programmer Jan 23 '23 at 14:24
  • Oops, hang on, it ends up with two arguments to `-c` ... I'll try to come up with a better fix. – tripleee Jan 23 '23 at 14:29