5

I am trying to print my mac's [edit: Apple computer] serial number in a java program. I am familiar with the Unix command

ioreg -l | awk '/IOPlatformSerialNumber/ { print $4;}'

which accomplishes this task in terminal.
When I try

String command = "ioreg -l | awk '/IOPlatformSerialNumber/ { print $4; }'"
Runtime terminal = Runtime.getRuntime(); 
String input = new BufferedReader(
    new InputStreamReader(
        terminal.exec(commands).getInputStream())).readLine();
System.out.println(new BufferedReader(
    new InputStreamReader(
        terminal.exec(command, args).getInputStream())).readLine());

my serial number is not printed. Instead it prints:

<+-o Root class IORegistryEntry, id 0x100000100, retain 10>  

I think the problem is that terminal.exec() is not meant to take the whole command string. Is there something in java similar to the argument shell = True in python's Popen(command, stdout=PIPE, shell=True) that will allow me to pass the whole command string?

skaffman
  • 398,947
  • 96
  • 818
  • 769
Alex Ramek
  • 51
  • 1
  • 3

3 Answers3

9

I see two possibilities:

  1. Parse the output of ioreg -l using, say, Scanner.

  2. Wrap the command in a shell script and exec() it:

#!/bin/sh
ioreg -l | awk '/IOPlatformSerialNumber/ { print $4;}'

Addendum: As an example of using ProcessBuilder, and incorporating a helpful suggestion by Paul Cager, here's a third alternative:

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class PBTest {

    public static void main(String[] args) {
        ProcessBuilder pb = new ProcessBuilder("bash", "-c",
            "ioreg -l | awk '/IOPlatformSerialNumber/ { print $4;}'");
        pb.redirectErrorStream(true);
        try {
            Process p = pb.start();
            String s;
            // read from the process's combined stdout & stderr
            BufferedReader stdout = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
            while ((s = stdout.readLine()) != null) {
                System.out.println(s);
            }
            System.out.println("Exit value: " + p.waitFor());
            p.getInputStream().close();
            p.getOutputStream().close();
            p.getErrorStream().close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I should add that [ProcessBuilder](http://download.oracle.com/javase/6/docs/api/java/lang/ProcessBuilder.html), discussed [here](http://stackoverflow.com/questions/5696404), is a more recent alternative to `exec()`. – trashgod Apr 21 '11 at 07:15
3

Pipes aren't supported by Runtime.exec(..) since they are a feature of shells. Instead, you'd have to emulate the pipe yourself, e.g.

String ioreg = toString(Runtime.exec("ioreg -l ").getInputStream());

Process awk = Runtime.exec("awk '/IOPlatformSerialNumber/ { print $4;}'");
write(awk.getOutputStream(), ioreg);

String input = new BufferedReader(new InputStreamReader(awk.getInputStream())).readLine();

Alternatively, you could of course run a shell as a process, e.g. Runtime.exec("bash"), and interact with it by reading and writing its IO streams. Interacting with processes is a bit tricky though and has some gotchas and let it execute your command (see comments)

sfussenegger
  • 35,575
  • 15
  • 95
  • 119
  • 2
    There's no need to emulate the pipe in Java, or interact with the shell's stdin/out. You could just use exec("bash -c 'ioreg -l | awk...'") – Paul Cager Apr 21 '11 at 10:10
  • @Paul true, of course. My main point was to make clear that pipes don't work with Runtime.exec(..) (unless it's used to run a shell) – sfussenegger Apr 21 '11 at 14:32
  • @Paul Cager: Excellent idea! I've incorporated it in an [example](http://stackoverflow.com/questions/5740673) using `ProcessBuilder`. @sfussenegger +1 for a useful alternative. – trashgod Apr 21 '11 at 14:48
1

To get the MAC addres via Java you can use java.net.NetworkInterface:

NetworkInterface.getByName("xxx").getHardwareAddress()

If you don't know the name (I assume it to be 'eth0' on linux) of your network interface, you can even iterate throug all of your network interfaces using NetworkInterface.getNetworkInterfaces().

BertNase
  • 2,374
  • 20
  • 24
  • Thank you for the speedy answer, but I think I wasn't perfectly clear. I am trying to print the serial number of my Apple computer, not my MAC address. Maybe I mistagged the post. – Alex Ramek Apr 21 '11 at 06:56
  • ah, OK. In this case your use of Runtime.exec could be the simplest thing. The only thing you need to change, is to separate all arguments and the command and put all them into a String[] which is passed into Runtime.exec as array. I am however not sure whether the piping of one comand's output into another command can actually be done using Runtime.exec, as this is a shell feature and actually involves starting two processes, not one. You could, however execute only `ioreg -l` in java and read the full output un do the filtering in java by iterating the output lines and using String.indexOf – BertNase Apr 21 '11 at 07:01