Question

How to access the unix shell special variables using java.

Few examples of unix shell special variables:

echo $$ which prints the process ID (PID) of the current shell.

echo $0 which prints the name of the command currently being executed.

echo $? which prints the exit status of the last command executed as a decimal string.

When these shell variables are included in a script file and passed the script file in ProcessBuilder argument, I'm able to execute it successfully using java. But when these variables are passed as arguments, these are not treated as variables itself. Why? How to access these special shell variables?

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class ExecSpecVars {

    public static void main(String a[]){

        InputStream is = null;
        ByteArrayOutputStream baos = null;

        List<String> list = new ArrayList<String>();
    //  String command ="/home/csk/sptest.sh"; 
        String command ="echo $$"; //This should print the PID instead of the string "$$".

        String cmd[] = command.split(" ");

        for (int i = 0; i < cmd.length; i++) {
            list.add(cmd[i]);
        }

        ProcessBuilder pb = new ProcessBuilder(list);
        try {
            Process prs = pb.start();
            is = prs.getInputStream();
            byte[] b = new byte[1024];
            int size = 0;
            baos = new ByteArrayOutputStream();
            while((size = is.read(b)) != -1){
                baos.write(b, 0, size);
            }
            System.out.println(new String(baos.toByteArray()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            try {
                if(is != null) is.close();
                if(baos != null) baos.close();
            } catch (Exception ex){}
        }
    }
}

sptest.sh file contains the below commands:

echo $$
echo $?
echo $0

Run this java class to test the shell special variables in the script file: uncomment the below line:

String command ="/home/csk/sptest.sh";

Comment the below line:

String command ="echo $$";
Was it helpful?

Solution

This is because the echo command is not resolving the $$ but bash is.

As Java does not run the command in the bash shell, this does not work.

If you run the command in bash then it will work, but it won't return what you might expect; it will return information about bash rather than the Java process:

/bin/bash -c 'echo $$' -> pid of bash process
/bin/bash -c 'echo $?' -> bash exit code
/bin/bash -c 'echo $0' -> /bin/bash

This is because you are now running another command ('/bin/bash') and the information given is about that command rather than your JVM.

In short, there is no easy way to do the things you want in Java.

Here's a quick test case to prove this (code significantly tidied and using Guava):

public static void main(final String[] args) throws Exception {
    System.out.println(ManagementFactory.getRuntimeMXBean().getName());
    runCommand("/bin/bash", "-c", "echo $$");
    runCommand("/bin/bash", "-c", "echo $?");
    runCommand("/bin/bash", "-c", "echo $0");
}

private static void runCommand(String... command) throws IOException {
    ProcessBuilder pb = new ProcessBuilder(command);
    Process prs = pb.start();
    try (InputStream is = prs.getInputStream()) {
        byte[] b = ByteStreams.toByteArray(is);
        System.out.println(new String(b, StandardCharsets.UTF_8));
    }
}

Output:

4466@krypto.local
4467

0

/bin/bash

So you can see that the pid is one higher than the JVM pid. And the program name is '/bin/bash'.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top