Command-Line JXA: run, read arguments, print, exit

#!/usr/bin/env osascript -l JavaScript

// Demonstration of running a JXA script as a command-line executable
// Mitchell L Model, dev@software-concepts.org, 2017-01-22

// Run by typing name of the script and arguments at the command-line.
// (Don't forget to make script executable.)
//

// based on:
//     https://github.com/dtinth/JXA-Cookbook/wiki/Shell-and-CLI-Interactions

// NSProcessInfo:
//     https://developer.apple.com/reference/foundation/nsprocessinfo
// NSProcessInfo.processInfo.arguments:
//     https://developer.apple.com/reference/foundation/
//                             nsprocessinfo/1415596-arguments?language=objc

ObjC.import('stdlib')                               // for exit

var args = $.NSProcessInfo.processInfo.arguments    // NSArray
var argv = []
var argc = args.count
for (var i = 4; i < argc; i++) {
    // skip 3-word run command at top and this file's name
    console.log($(args.objectAtIndex(i)).js)       // print each argument
    argv.push(ObjC.unwrap(args.objectAtIndex(i)))  // collect arguments
}
console.log(argv);                                 // print arguments
$.exit(0)

1 Like

This is really nice, I’m surprised there’s no comments on it as of yet. But making applications automatable via command line is super important IMO. So this is a great example to kick us off!

Thanks,

It's possible this is the wrong forum for it. Since we can pass KM parameters to JXA scripts, there's less of a need to use command-line parameters.

Obviously, though, there are certainly good reasons to use them. It's just that in the KM forum, most of us aren't going to need them very often.

Hence, the lack of comments.

1 Like

Another lightish way to do this is to bypass the ObjC mechanics and use Bash argument variables directly:

#!/bin/bash

osascript -l JavaScript <<JXA_END 2>/dev/null
(function () {
    'use strict';

    // Shell script name, arg1 arg2 ... argN
    return ['$0', $1, $2];

})();
JXA_END

$1 and $2 above are unquoted because I am passing number arguments to the command line

I realize you were responding to @sancarn, not objecting to my posting the script. (Or at least I hope so :sweat:.) But your comment suggests that some elaboration is in order.

Technically, we don't exactly “pass parameters” to JXA — or to AppleScript. What we do is put them somewhere where the script knows to look for them. More like a mail drop then passing. Command-line input is a different, and more flexible, mechanism.

There are three dimensions to why you might want a KM-independent command-line JXA program: input, execution, and output. Here are some examples from my experimentation with command-line JXA:

  • *Input: You wrote a JXA program that you — not a macro — sometimes run from the command-line, so it needs a way to get its parameters independently of KM variables.. Perhaps the input is piped from another program. If you also want to invoke the script from a macro you would do that with an Execute Shell Script action rather than an Execute a JavaScript for Automation.
    .

  • Execution: You wrote a JXA program that uses Foundation classes to do something relevant to KM, but not something it makes sense to invoke through a KM trigger — for instance, list all your groups and macros. (You might have written the program in Objective-C or Swift, but chose JXA for one reason or another.)

  • Output: Your program produces a lot of output, which would be inconvenient to view in a KM window. You might also need to pipe the output to another program or a file. There’s no particular reason to invoke this with a KM trigger, but again, you could do so through Execute Shell Script action.

In general, KM variables are not a comfortable fit for scripts with large amounts of input or output. (The considerations listed in the bullets above apply also to AppleScript.)

Finally, in practice this forum is in part a place for us to share knowledge about scripting, not just writing KM macros, and the above is a piece of scripting knowledge. I could also show you how to write a command-line program in Objective-C or Swift, but as those are not scripting languages it probably wouldn't be appropriate to do so on this forum.

You're correct. :slight_smile: I was merely stating why I thought you hadn't received any comments.

As for the rest of your comments, I get it exactly. Spot-on, and a good explanation of why you wrote this code.

While we’re at it, I couldn’t resist: Command-Line AppleScript: run, read arguments, print, exit.

1 Like