0

I'm trying select a part of some output in Bash, but can't figure out where to place the filter and am confused about the output I'm getting.

I'm starting from

declare -a pythons=("python" "python2" "python3")
for p in "${pythons[@]}"
do
   echo "$p: $($p --version 2>&1) in $(which $p)"  && for i in $(which -a $p); do echo "    $i ($($i --version 2>&1))"; done && echo; 
done

which has worked for years to produce the output I expect, namely

python: Python 2.7.15 in /usr/local/bin/python
    /usr/local/bin/python (Python 2.7.15)
    /usr/bin/python (Python 2.7.10)

python2: Python 2.7.15 in /usr/local/bin/python2
    /usr/local/bin/python2 (Python 2.7.15)

python3: Python 3.7.0 in /usr/local/bin/python3
    /usr/local/bin/python3 (Python 3.7.0)

but now produces

python3: Python 3.7.0 (default, Jun 29 2018, 20:13:13) 
[Clang 9.1.0 (clang-902.0.39.2)] in /usr/local/bin/python3
    /usr/local/bin/python3 (Python 3.7.0 (default, Jun 29 2018, 20:13:13) 
[Clang 9.1.0 (clang-902.0.39.2)])

for the final grouping.

I'd thought that I could simply fix this by adding egrep -o 'Python\s[0-9\\.]+' right after each python --version with

for p in "${pythons[@]}"
do
   echo "$p: $($p --version | egrep -o 'Python\s[0-9\\.]+' 2>&1) in $(which $p)"  && for i in $(which -a $p); do echo "    $i ($($i --version | egrep -o 'Python\s[0-9\\.]+' 2>&1))"; done && echo; 
done

but this surprises me by pulling the Python 2 versions out onto a separate line before lines where I expect it

Python 2.7.15
python:  in /usr/local/bin/python
Python 2.7.15
    /usr/local/bin/python ()
Python 2.7.10
    /usr/bin/python ()

Python 2.7.15
python2:  in /usr/local/bin/python2
Python 2.7.15
    /usr/local/bin/python2 ()

python3: Python 3.7.0 in /usr/local/bin/python3
    /usr/local/bin/python3 (Python 3.7.0)

I think I've totally lost my bearings about where output is being sent, and need help sorting out where I'm making my — probably very basic — Bash scripting mistake.

orome
  • 45,163
  • 57
  • 202
  • 418
  • have you tried the raw `which -a python` / python 2 / python 3 commands and see the result? something must have changed in your system. – Jean-François Fabre Sep 01 '18 at 19:18
  • @Jean-FrançoisFabre Yes and they seem unchanged. And how would they matter here? For example I can have just `echo "$p: $($p --version | egrep -o 'Python\s[0-9\\.]+' 2>&1) " ` in the `do` and get the same behavior I'm seeing. – orome Sep 01 '18 at 19:27
  • I don't understand why you're double-escaping the dot when you just simple escape the "s" in your regex – Jean-François Fabre Sep 01 '18 at 19:35
  • @Jean-FrançoisFabre Doesn't make any difference does it? – orome Sep 01 '18 at 19:38
  • Related, `(which $p)` should probably be avoided. Instead you should use `command -v`. Also see [How to check if a program exists from a Bash script?](https://stackoverflow.com/q/592620/608639) and [How to check if command exists in a shell script?](https://stackoverflow.com/q/7522712/608639) – jww Sep 01 '18 at 20:12

1 Answers1

1

The issue seems to be related to the fact that you shifted the position of 2>&1 to the right of grep. Use this one:

for p in "${pythons[@]}"
do
   echo "$p: $($p --version 2>&1 | egrep -o 'Python\s[0-9\\.]+') in $(which $p)" && for i in $(which -a $p); do echo "    $i ($($i --version 2>&1 | egrep -o 'Python\s[0-9\\.]+'))"; done && echo; 
done
orome
  • 45,163
  • 57
  • 202
  • 418
codeforester
  • 39,467
  • 16
  • 112
  • 140