21

I am using osascript in Bash to display a message in Notification Center (Mac OS X) via Apple Script. I am trying to pass a text variable from Bash to the script. For a variable without spaces, this works just fine, but not for one with spaces:

Defining

var1="Hello"
var2="Hello World"

and using

osascript -e 'display notification "'$var1'"'

works, but using

osascript -e 'display notification "'$var2'"'

yields

syntax error: Expected string but found end of script.

What do I need to change (I am new to this)? Thanks!

Bernd
  • 675
  • 3
  • 13
  • 23

2 Answers2

36

You could try to use instead :

osascript -e "display notification \"$var2\""

Or :

osascript -e 'display notification "'"$var2"'"'

This fixes the problem of manipulation of variables that contains spaces in bash. However, this solution doesn't protect against injections of osascript code. So it would be better to choose one of Charles Duffy's solutions or to use bash parameter expansion :

# if you prefer escape the doubles quotes
osascript -e "display notification \"${var2//\"/\\\"}\""
# or
osascript -e 'display notification "'"${var2//\"/\\\"}"'"'

# if you prefer to remove the doubles quotes
osascript -e "display notification \"${var2//\"/}\""
# or
osascript -e 'display notification "'"${var2//\"/}"'"'

Thank to mklement0 for this very useful suggestion !

SomeGuyOnAComputer
  • 5,414
  • 6
  • 40
  • 72
Idriss Neumann
  • 3,760
  • 2
  • 23
  • 32
  • This isn't safe to use with untrusted data: Consider what happens when `var2` contains literal `"` characters. – Charles Duffy May 28 '14 at 22:54
  • @CharlesDuffy I don't know `osascript`. However in bash scripting, we must always protect our variables by using double quotes in most cases (because of the default IFS). Data consistency and security for `osascript` is not addressed in my answer and it's not the subject although I assume that there are risks of injections as for other technologies. In bash scripting, it's not a problem to have a string which contain double quotes. – Idriss Neumann May 28 '14 at 23:04
  • I didn't say it was a bash problem, I said it was an injection problem. Think Bobby Tables -- this is the local equivalent of `"SELECT * FROM USERS WHERE name='$foo'"`, and dangerous for all the same reasons. – Charles Duffy May 28 '14 at 23:18
  • ...to clarify the Bobby Tables reference: http://xkcd.com/327/; to clarify the security bug: think about what happens with your solution when `var2='message to print"; command("rm -rf /"); display notification "'` (or whatever the exact osascript syntax is for that). – Charles Duffy May 28 '14 at 23:19
  • 1
    ...and as for "X is not addressed by this answer" -- just as any answer for generating SQL that allowed injection bugs should be subject to jeers from the crowd, answers for a question on how to properly interface between bash and osascript that don't actually take proper/safe use of osascript into account have good cause to be similarly rejected. – Charles Duffy May 28 '14 at 23:25
  • @CharlesDuffy You're right, I would have reacted the same way if it were an unsecured SQL query. I'll add a note in my answer. – Idriss Neumann May 28 '14 at 23:29
  • @CharlesDuffy I've updated my answer and gave +1 to your answer ;) – Idriss Neumann May 28 '14 at 23:36
  • 2
    @CharlesDuffy: I wouldn't know how to _inject_ code in this instance (AppleScript doesn't allow placing multiple commands on 1 line; in general, though, the concern about injection is appreciated); in particular, however, the concern about values containing `"` is valid (in terms of _breaking_ the command); here's the (somewhat cumbersome) remedy, using `bash` parameter expansion: `osascript -e "display notification \"${var2//\"/\\\"}\""` – mklement0 May 29 '14 at 02:34
  • @mklement0, AppleScript *does* allow string concatenation, though -- I'd think that `var2='" & arbitrary_command & "'` would do the trick, even if you don't have a `;`-equivalent operator. – Charles Duffy May 29 '14 at 13:46
  • @CharlesDuffy: I wasn't referring to _string_ concatenation, I was referring to placing _multiple statements on a single line_ (single `-e` option) - which, it seems to me, would be the only way to execute arbitrary code in this scenario. AppleScript does have a feature akin to `eval` - `run script` - but that would obviously also require a separate command. I'm genuinely curious: can you come up with an injection example? – mklement0 May 29 '14 at 13:54
  • @mklement0, `var2='hello world" & do shell script "touch /tmp/created" & "'; osascript -e 'display notification "'"$var2"'"' `; when I run that, I get `/tmp/created` on disk. Which is to say that post-escape string concatenation can, in practice, be used to run arbitrary code. – Charles Duffy May 29 '14 at 16:07
  • 1
    @IdrissNeumann, would you consider adopting mklement0's suggestion re: using parameter expansion to escape any double quotes? I'd feel a lot more comfortable with your answer at the top of the page were that done. – Charles Duffy May 29 '14 at 16:25
  • 1
    @CharlesDuffy Well done, hadn't thought of that. With _escaped double quotes_, however, as I suggested (`${var2//\"/\\\"}`), this exploit will NOT work - or do you see a way around that, too? – mklement0 May 29 '14 at 18:58
  • 1
    @mklement0, ...and that's why I asked Idriss to incorporate your suggestion, rather than to withdraw the answer. I don't have an immediate escape for that, though if I were going to try to create one, I'd probably start poking around Unicode character set conversion logic (being a common weak point), and/or reading the formal language spec. – Charles Duffy May 29 '14 at 19:20
  • ...well, what I'd _really_ do in practice would probably be to ask someone on the reverse engineering team at work to take a shot at it. :P – Charles Duffy May 29 '14 at 19:23
  • ...as an aside: Part of the reason I'm maintaining my own answer, rather than entirely endorsing this one as amended, is that despite using the Bobby Tables XKCD link to demonstrate injection attacks to others, I actually object to it somewhat: "Sanitiz[ing] inputs", but still mixing syntax and data, is a far weaker safety measure than segregating user-provided data from syntax entirely. – Charles Duffy May 29 '14 at 20:55
  • Oddly enough, I'm using the $SRCROOT variable calling a shell script to open a Terminal window from an Xcode project. Nothing listed above allows me to display dialog with the $SRCROOT value in the message body. The dialog doesn't display at all when attempting to add $SRCROOT. The code below works as expected, but not when adding $SRCROOT to replace message. `osascript -e 'display dialog "message" with title "Hi"'` `open -a Terminal "$SRCROOT"` – Alex Zavatone Jan 30 '23 at 16:58
20

This version is completely safe against injection attacks, unlike variants trying to use string concatenation.

osascript \
  -e "on run(argv)" \
  -e "return display notification item 1 of argv" \
  -e "end" \
  -- "$var2"

...or, if one preferred to pass code in on stdin rather than argv:

osascript -- - "$var2" <<'EOF'
  on run(argv)
    return display notification item 1 of argv
  end
EOF
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 1
    +1 for a robust solution for passing arbitrary arguments to `osascript` safely from the command line (though it may be overkill for the case at hand). – mklement0 May 29 '14 at 03:34
  • Thanks for the more robust solution - I ended up accepting the other one since it is sufficient for the case at hand, where no injection attacks or variables with ` are to be expected. – Bernd May 29 '14 at 07:55
  • 4
    There's no real reason *not* to use proper, safe code; when you don't expect an attack is when you are most vulnerable to it. – chepner May 29 '14 at 16:55
  • As an aside: the `on run argv` line works, despite not enclosing the argument - `argv` - in parentheses, which is normally required in AppleScript handlers. This curious syntax exception - which only works with handler name `run` - has been around for a long time (and therefore probably won't go away). The non-exceptional syntax works too, however: `on run(argv)`. – mklement0 May 29 '14 at 20:45
  • @chepner: Excellent point. Fortunately, those variants of the accepted answer _with escaping or removal of double quotes_ should be safe. – mklement0 May 29 '14 at 20:49
  • apologies if I should rather have "accepted" the other answer - I just clicked on the one which I ended up using. Should I change the accepted answer so that others with a similar problem come to the "safer" solution right away? – Bernd Jun 02 '14 at 15:19
  • @Bernd, now that the other answer has been amended to show a safer approach, it's probably OK to leave as-is... and I say "probably" only because it retains the unsafe first approach rather than showing exclusively the latter two answers now given (which are, if not certainly safe, at least probably safe). – Charles Duffy Jun 02 '14 at 15:22