Search code examples
bashapplescript

osascript how to pass in a variable


I have the following, not working. It opens up a new tab in Terminal but the variable $DomainName is not passed in?

DomainName="example.com"
osascript -e 'tell application "Terminal" to do script "watch dig +short NS $DomainName"'

Outcome is:

watch dig +short NS $DomainName

How do you pass in a variable?


Solution

  • OP’s question is a masterclass in how [not to] sanitize shell script inputs when calling osascript.

    This is dangerously unsafe:

    foo="DO NOT DO THIS; say bad script"
    osascript -e "tell application \"Terminal\" to do script \"echo $foo\""
    

    (Run that example to see what I mean, then consider what a less friendly string could wreak.)

    Double-quoting the variable $foo as "$foo" gets it safely through the top-level shell script. It does NOT get it safely through the AppleScript:

    foo="say \"bad script\""
    osascript -e "tell application \"Terminal\" to do script \"echo $foo\""
    

    If you run that example, it will fail with an AppleScript compilation error: A identifier can’t go after this “"”. (-2740)

    That’s because osascript receives the string:

    tell application "Terminal" to do script "echo say "bad script""
    

    which is invalid syntax. (Try compiling that line in Script Editor to see.)

    The correct way to pass AppleScript arguments is by appending them to osascript’s arguments list:

    osascript -ss -e "…" - "arg1" "arg2" "arg3"
    

    The - separator is required to separate the command’s own options list from the remaining arguments to be forwarded to the AppleScript’s run handler.

    BTW, is also a good idea to pass the AppleScript via osascript’s stdin instead of -e options, as that lets you write normal AppleScript code without having to escape it as well:

    osascript -ss - "arg1" "arg2" "arg3" <<EOF
    
        on run argv -- argv is a list of 3 strings
            argv -- do stuff with argv here
        end run
    
    EOF
    

    (You can run that example safely: it just writes the value of argv to stdout.)

    Okay, so that’s safe as far as passing arguments into AppleScript goes.

    ..

    However, OP’s AppleScript creates a new shell script to be run in Terminal.app. Therefore, it is also essential to sanitize the AppleScript strings used to construct that shell script, which is done using AppleScript’s quoted form of STRING property.

    So here is the correct safe way to sanitize arbitrary strings through all three levels of code generation:

    bar='$test" \t#est*;say bad script' # a proper nasty test string
    
    osascript -  "$bar"  <<EOF
    
        on run argv -- argv is a list of strings
            tell application "Terminal"
                do script ("echo " & quoted form of item 1 of argv)
            end tell
        end run
    
    EOF
    

    Run that example, and the fairly horrible test string I’ve used here is passed safely all the way to echo.

    And yes, all this string sanitization/code generation stuff is a headache, but that’s what you get for using so many languages designed by crazy people.