Detect command line invocation of a sketch?

I have a sketch that I want to

  1. launch and run from PDE / app
  2. launch, run once, and quit from the command line

In order to do this I need to detect whether it was run from the command line!

Currently I can assume a command line invocation if there are args present.

However, I would like to detect command line invocation even if there are no args. Is that possible?

boolean exitWhenDone;

void setup() {
  // detect command line invocation if args present
  if (args != null) {
    // default command line behavior - run and quit
    exitWhenDone = true;
    // override default with command line argument
    for (String arg : args) {
      if ("noexit".equals(arg)) {
        exitWhenDone=false;
      }
    }
  }
}

void draw() {
  if (exitWhenDone) {
    exit();
  }
}

The sketch detects CL invocation with any throwaway placeholder arg, e.g.

processing-java --sketch=`pwd`/CLTest --run myarg

It doesn't work without, because args is null:

processing-java --sketch=`pwd`/CLTest --run

Answers

  • What operating system is this? 8)

  • edited September 2017

    Hah!

    macOS 10.12.6 (Sierra)

    $ echo $SHELL
    /bin/bash
    $ bash --version
    GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)
    $ processing-java --help | head -2

    Command line edition for Processing 0262 (Java Mode)

  • edited September 2017

    this works in linux ("null" when run with ctrl-r in pde, prints the arg if run with ./tmpArgs whatever)

    void setup() {
      println(args == null ? "null" : args);
    }
    

    oh, that's what you currently have...

  • edited September 2017

    Great! I'm trying to have the sketch distinguish between:

    1. ctrl-r in pde
    2. run with ./tmpNoArgs -- no args

    In other words "Was I run from the command line with no args, or from PDE?"

  • edited September 2017 Answer ✓
    void setup() {
      println(args == null ? "null" : args);
      //println(System.getProperties());
      println(System.getProperty("sun.java.command"));
    }
    

    that last one looks promising

  • Answer ✓

    ah, ok, i was running an exported app vs the pde. the processing-java version does a different sun.java.command again (ie can distinguish the three cases)

    (as an aside, the linux export creates an additional shell script containing the following:

    #!/bin/sh
    
    APPDIR=$(readlink -f "$0")
    APPDIR=$(dirname "$APPDIR")
    java -Djna.nosys=true -Djava.library.path="$APPDIR:$APPDIR/lib" -cp "$APPDIR:$APPDIR/lib/tmpArgs.jar:$APPDIR/lib/core.jar:$APPDIR/lib/jogl-all.jar:$APPDIR/lib/gluegen-rt.jar:$APPDIR/lib/jogl-all-natives-linux-amd64.jar:$APPDIR/lib/gluegen-rt-natives-linux-amd64.jar" tmpArgs "$@"
    

    }

    where tmpArgs is the sketch name)

  • Excellent -- System.getProperty("sun.java.command") looks like exactly what I needed. Many thanks, @koogs.

  • the name suggests that it's an oracle thing. but it's in both the pde and command line version (the former is using openjdk, the latter oracle)

  • edited September 2017

    So, it turns out that if a sketch was called from PDE it will have been passed the flag "--external" -- if from the command line, not. Documented here:

    Parameters used by Processing when running via the PDE
    "--external": set when the applet is being used by the PDE

    Parsing System.getProperty("sun.java.command") for that flag will detect PDE.

    This is a reliable way to distinguish between a sketch being run in PDE or the command line even without using command line arguments.

    I'm not yet sure how this affects exported applications, however.

  • edited September 2017

    Here is a demo sketch that combines reliable no-argument detection with argument parsing:

    /**
     * CommandLineDetect
     * 2017-09-21 Jeremy Douglass - Processing 3.3.6 
     * Was a sketch run from PDE, or from the command line?
     * If from the command line, what are its arguments and their values?
     * 
     * Invoke it:
     * 1. from the command line above the sketch folder, with no arguments:
     *     processing-java --sketch=`pwd`/CommandLineDetect --run
     * 2. ...or with arguments:
     *     processing-java --sketch=`pwd`/CommandLineDetect --run foo bar=baz lorem="ipsum dolor sit amet, consectetur adipiscing elit" etc 
     * 3. or form PDE
     *
     * The sketch relies on the --external flag to detect a PDE launch, as per:
     * - processing.github.io/processing-javadocs/core/processing/core/PApplet.html#main-java.lang.String:A-
     * 
     * The command line passes in a String[] of args. If you wish to arguments of the:
     *  -  form foo=bar
     *  -  lorem="ipsum dolor"
     * 
     * Related forum discussions:
     * -  forum.processing.org/two/discussion/23999/detect-command-line-invocation-of-a-sketch
     * -  forum.processing.org/two/discussion/23924/handling-command-line-arguments-in-a-sketch
     * -  forum.processing.org/two/discussion/6457/how-to-use-arguments-with-an-application-built-with-processing
     */
    
    boolean PDE;
    StringDict argDict = new StringDict();
    
    void setup() {
    
      // get invocation string
      String cmd = System.getProperty("sun.java.command");
      // check if launched from PDE
      if (cmd.contains("--external")) {
        PDE=true;
      } else {
        PDE=false;
      }
    
      // if there are command line arguments, print them:
      println(args == null ? "null" : args);
    
      // load command line arguments, load them
      if (args != null) {
        for (String arg : args) {
          String[] entry = split(arg, "=");
          if (entry.length == 1) {
            argDict.set(entry[0], "");
          }
          if (entry.length == 2) {
            argDict.set(entry[0], entry[1]);
          }
        }
      }
    
      // set default if specific arg not present
      if (!argDict.hasKey("xyzzy")) {
        println("Setting default for xyzzy");
        // ...do something
      }
    
      // demonstrate using arguments
      for (String arg : argDict.keyArray()) {
        switch(arg) {
        case "foo":
          // key only arg
          println("mode:", arg);
          // ...do something
          break;
        case "bar":
          // key=value arg
          println("Setting", arg, "=", argDict.get(arg));
          // ...do something
          break;
        case "lorem":
          // parsed value
          String parsed = join(sort(argDict.get(arg).split(" ")), " ");
          println("Sorting", arg, "=", parsed);
          // ...do something
          break;
        }
      }
      exit();
    }
    
Sign In or Register to comment.