7

I need to get the java version number, for example "1.5", from python (or bash).

I would use:

os.system('java -version 2>&1 | grep "java version" | cut -d "\\\"" -f 2')

But that returns 1.5.0_30

It needs to be compatible if the number changes to "1.10" for example.

I would like to use cut or grep or even sed. It should be in one line.

jteichert
  • 527
  • 1
  • 4
  • 20
  • 3
    *"It needs to be compatible"* - with what? What are you actually trying to achieve? *"It should be in one line"* - why? – jonrsharpe Aug 04 '15 at 11:20
  • compatible with newer java versions. And in one line to keep the code clean. – jteichert Aug 04 '15 at 11:21
  • 2
    Why do you think that it will break with e.g. `"1.10"`? You're running a terminal command via `os.system`, I think *"clean"* has been and gone... – jonrsharpe Aug 04 '15 at 11:22
  • 1
    @jteichert one-liners aren't necessarily clean code. – Peter Wood Aug 04 '15 at 11:23
  • @fedorqui i need just the major and minor version. The reason is, that this has to go into the build function of a waf script. That only accepts major.minor version (at least it didnt work just now when I used 1.5.0) `bld(features = 'javac jar', compat = '1.5', ... )` – jteichert Aug 04 '15 at 11:35

6 Answers6

20

The Java runtime seems to send the version information to the stderr. You can get at this using Python's subprocess module:

>>> import subprocess
>>> version = subprocess.check_output(['java', '-version'], stderr=subprocess.STDOUT)

>>> print version
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) Client VM (build 24.79-b02, mixed mode)

You can get the version out with a regex:

>>> import re
>>> pattern = '\"(\d+\.\d+).*\"'

>>> print re.search(pattern, version).groups()[0]
1.7

If you are using a pre-2.7 version of Python, see this question: subprocess.check_output() doesn't seem to exist (Python 2.6.5)

Community
  • 1
  • 1
Peter Wood
  • 23,859
  • 5
  • 60
  • 99
  • 2
    very nice one! I learnt a lot from it, better than my calling to external `awk`. – fedorqui Aug 04 '15 at 11:47
  • This is the right answer. Keep the subprocess as simple as possible (just get the output from `java`), and process the resulting string in Python. – chepner Aug 04 '15 at 11:47
  • thanks, one remark: subprocess only worked when I replaced `check_output` with `check_call`. I have python 2.6 installed. – jteichert Aug 04 '15 at 12:43
  • @jteichert I've updated the answer with a link to [a question](http://stackoverflow.com/questions/4814970/subprocess-check-output-doesnt-seem-to-exist-python-2-6-5) about missing `check_output`, pre-2.7. – Peter Wood Aug 04 '15 at 14:09
  • @PeterWood ah thank you very much for the workaround for pre 2.7 versions of python. – jteichert Aug 05 '15 at 08:27
  • Does subprocess.Popen use another environment than my current shell? I want to use the java version that i specified with my JAVA_HOME path (in .bashrc). But thats another one than I am getting with this command. – jteichert Aug 05 '15 at 09:03
  • @jteichert See [Python and environment variables](http://stackoverflow.com/questions/10885251/python-and-environment-variables). – Peter Wood Aug 05 '15 at 09:36
  • @jteichert Also, [How to use the bash shell with Python's subprocess module instead of /bin/sh](http://www.saltycrane.com/blog/2011/04/how-use-bash-shell-python-subprocess-instead-binsh/). – Peter Wood Aug 05 '15 at 09:37
  • 1
    If you have set `JAVA_TOOL_OPTIONS` env variable then java will print the options before the actual result, which might break your regex later. – Fabich Oct 22 '19 at 15:55
4

Considering an output like this:

$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

You can get the version number with awk like this:

$ java -version 2>&1 | awk -F[\"_] 'NR==1{print $2}'
1.8.0

Or, if you just want the first two .-separated digits:

$ java -version 2>&1 | awk -F[\"\.] -v OFS=. 'NR==1{print $2,$3}'
1.8

Here, awk sets the field separator to either " or _ (or .), so that the line is sliced in pieces. Then, it prints the 2nd field on the first line (indicated by NR==1). By setting OFS we indicate what is the output field separator, so that saying print $2, $3 prints the 2nd field followed by the 3rd one with a . in between.

To use it in Python you need to escape properly:

>>> os.system('java -version 2>&1 | awk -F[\\\"_] \'NR==1{print $2}\'')
1.8.0
>>> os.system('java -version 2>&1 | awk -F[\\\"\.] -v OFS=. \'NR==1{print $2,$3}\'')
1.8
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • You can't capture the child's output with `os.system()`, so this method is less practical than others. – mhawke Aug 04 '15 at 12:02
  • @mhawke Not sure why child's output may be necessary here. Also, as I said below Peter Wood's answer, I also thing his answer is superior since it uses Python entirely. – fedorqui Aug 04 '15 at 12:05
  • Surely the child's output is necessary if you actually want to do anything with the version number obtained. – mhawke Aug 04 '15 at 12:11
  • You really want to avoid `os.system()` and Awk here. The `subprocess` answer should be the accepted one. – tripleee May 20 '19 at 13:59
1

You can't capture the command's output with os.system(). Instead, use subprocess.check_output():

>>> import subprocess
>>> java_version = subprocess.check_output(['java', '-version'], stderr=subprocess.STDOUT)
>>> java_version
'openjdk version "1.8.0_51"\nOpenJDK Runtime Environment (build 1.8.0_51-b16)\nOpenJDK 64-Bit Server VM (build 25.51-b03, mixed mode)\n'

Now that you can collect the command output, you can extract the version number using Python, rather than piping through other commands (which, incidentally, would require use of the less secure shell=True argument to check_output).

>>> version_number = java_version.splitlines()[0].split()[-1].strip('"')
>>> major, minor, _ = version_number.split('.')
>>> print 'Major: {}, Minor: {}'.format(major, minor)
Major: 1, Minor: 8
mhawke
  • 84,695
  • 9
  • 117
  • 138
1

You could let grep handle a regular expression:

java -version 2>&1 | grep -Eow '[0-9]+\.[0-9]+' | head -1
tobifasc
  • 681
  • 5
  • 17
1

It's an old post, but if someone needs it:

import subprocess
import re

javaPath = 'C:/.../java.exe'

javaInfo = subprocess.check_output(javaPath + ' -version', shell=True, stderr=subprocess.STDOUT)
javaVersion = re.search(r'"[0-9\._]*"', javaInfo.decode().split("\r")[0]).group().replace('"', '')

print(javaVersion)
John
  • 89
  • 1
  • 8
0

python

import os;

os.system("java -version 2>&1 | grep 'version' 2>&1 | awk -F\\\" '{ split($2,a,\".\"); print a[1]\".\"a[2]}'");

xxx=os.popen("java -version 2>&1 | grep 'version' 2>&1 | awk -F\\\" '{ split($2,a,\".\"); print a[1]\".\"a[2]}'").read();

print xxx
1.8
Pradeep
  • 9,667
  • 13
  • 27
  • 34