Jump to content

How to program a script filter with changing numbers of outputs


Recommended Posts

I am ashamed to admit that I have spent literally days working on this problem—because, however much I have read about them, script filters baffle me (as this humiliating post will clearly demonstrate).

 

Without more ado, although with much blushing 😊, here is where I am at present:

 

targets=($(grep -i $1 "${theFile}" | grep -i http))

subtitletext='Press enter to open'

cat << EOB
{"items": [
  {
    "title": "$targets[1]",
    "subtitle": "$subtitletext",
    "arg": "$targets[1]"
  },
  {
    "title": "$targets[2]",
    "subtitle": "$subtitletext",
    "arg": "$targets[2]"
  },
  {
    "title": "$targets[3]",
    "subtitle": "$subtitletext",
    "arg": "$targets[3]"
  },
  {
    "title": "$targets[4]",
    "subtitle": "$subtitletext",
    "arg": "$targets[4]"
  },
  {
    "title": "$targets[5]",
    "subtitle": "$subtitletext",
    "arg": "$targets[5]"
  }
]}
EOB

 

That is obviously quite ridiculous—even though, much to my surprise, it does actually work. What I need is to limit the JSON to the number of items output by the grep command. Sadly, my mind is now so battered with having got that far I have to come here, on bended knee, asking for something akin to divine intervention.

 

Please be gentle.

 

Stephen

Link to comment

Part of the issue is that shell languages (such as Zsh) don’t have facilities to properly deal with JSON and convert structured information simply with all escaping taken into account. So if you have (say) one of those targets with a ", sticking it in there from a variable may break the JSON. This is also one of the reasons I tend to discourage AppleScript. JavaScript for Automation (its counterpart) does not have the problem.


In other words, you can make the JSON purely in Zsh but it will be complicated and can have bugs. I’d recommend calling JavaScript for Automation temporarily just to deal with that part.

 

targets=($(grep -i $1 "${theFile}" | grep -i http))

osascript -l JavaScript -e 'function run(argv) {
  const sfItems = argv.map(argumentItem => ({
    title: argumentItem,
    subtitle: "Press enter to open",
    arg: argumentItem
  }))

  return JSON.stringify({ items: sfItems })
}' "${targets[@]}"

 

Note the "${targets[@]}" at the end. The argumentItem is where it’s replaced in the JSON.

 

You can try jq instead (brew install jq) which aims precisely to bring JSON editing to the command line, so you could e.g. pipe to it from the grep.

Link to comment

Many thanks for the kind reply. I'll give all that a shot when I have a little more time!

 

Edit: (Couldn't resist trying it!) Of course it works perfectly. Thanks so much. Now I'll devote my time to trying to understand how and why!

 

Stephen

Edited by Stephen_C
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...