Trouble escaping quotes in a shell script - bash

I have a bash script I am making that generates some numbers assignes them to variables then uses osascript to write them out in any application of choice.
Here is a simplified version of what I want to do.
monday1=5
osascript -e 'tell application "System Events" to keystroke "$monday1"'; \
The osascript should look like this
osascript -e 'tell application "System Events" to keystroke "5"'; \
This will then type out the number 5 in what ever app I have my cursor in. The problem is it outputs $monday1 instead. I know I have to do something to escape the quotes so the script can input the variable, but I'm not sure how.
Thoughts?

The problem is that inside single quotes, there are no special metacharacters, so $monday1 is passed to osascript unchanged. So, you have to make sure that $monday1 is not inside single quotes.
Your options include:
monday1=5
osascript -e 'tell application "System Events" to keystroke "'$monday1'"'
monday1=5
osascript -e 'tell application "System Events" to keystroke "'"$monday1"'"'
monday1=5
osascript -e "tell application \"System Events\" to keystroke \"$monday1\""
monday1=5
osascript -e "tell application 'System Events' to keystroke '$monday1'"
The first stops the single-quoting just after the double quote to surround the key stroke, embeds the value of $monday, and resumes the single-quoting for the remaining double quote. This works because there are no spaces etc in $monday1.
The second is similar to the first but surrounds "$monday1" in double quotes, so it will work even if $monday1 contained spaces.
The third surrounds the whole argument with double quotes, and escapes each embedded double quote. If you're not allergic to backslashes, this is good.
The fourth may or may not work — it depends on whether the osascript program is sensitive to the type of the quotes surrounding its arguments. It simply reverses the use of double quotes and single quotes. (This works as far as the shell is concerned. Gordon Davisson observes in a comment that osascript requires double quotes and does not accept single quotes, so it doesn't work because of the rules of the invoked program — osascript.)
In both the third and fourth cases, you need to be careful if there are other parts of the string that need to be protected so that the shell does not expand the information. In general, single quotes are better, so I'd use one of the first two options.

The single quotes form a scope without variable substitution.
osascript -e "tell application \"System Events\" to keystroke \"$monday1\""; \

Wrapping your entire string in single quotes prevents the variable monday1 from being interpolated. Switch your double and single quotes:
osascript -e "tell application 'System Events' to keystroke '$monday1'";

Related

Run 2 commands in applescript/osascript with variable

I am trying to run 2 commands stored in a variable with osascript
This is my start.sh
currentDirectory="cd $(pwd) && npm run start"
echo $currentDirectory
osascript -e 'tell application "Terminal" to do script '"${currentDirectory}"''
I am getting this as the output
sh start.sh
cd /Users/Picadillo/Movies/my-test-tepo && npm run start
83:84: syntax error: Expected expression but found “&”. (-2741)
#Barmar: The argument to do script needs to be in double quotes.
Yes; however, the way you’ve done it is still unsafe.
If the path itself contains backslashes or double quotes, AS will throw a syntax error as the munged AS code string fails to compile. (One might even construct a malicious file path to execute arbitrary AS.) While these are not characters that frequently appear in file paths, best safe than sorry. Quoting string literals correctly is always a nightmare; correctly quoting them all the way through shell and AppleScript quadratically so.
Fortunately, there is an easy way to do it:
currentDirectory="$(pwd)"
osascript - "${currentDirectory}" <<EOF
on run {currentDirectory}
tell application "Terminal"
do script "cd " & (quoted form of currentDirectory) & " && npm run start"
end tell
end run
EOF
Pass the currentDirectory path as an additional argument to osascript (the - separates any options flags from extra args) and osascript will pass the extra argument strings as parameters to the AppleScript’s run handler. To single-quote that AppleScript string to pass back to shell, simply get its quoted form property.
Bonus: scripts written this way are cleaner and easier to read too, so less chance of overlooking any quoting bugs you have in your shell code.
The argument to do script needs to be in double quotes.
osascript -e 'tell application "Terminal" to do script "'"${currentDirectory}"'"'
You should also put the argument to cd in quotes, in case it contains spaces.
currentDirectory="cd '$(pwd)' && npm run start"

Echo but retain all quotes

Is it possible to echo a text and keep all quotes and double quotes in place?
I want to write a function to copy the text currently written in the terminal (completely with quotes).
Since I am on OSX I have to use pbcopy:
pb(){echo "$#" | pbcopy}
But pb osascript -e 'tell Application "iTerm" to display dialog "Job finished"' does return
osascript -e tell Application "iTerm" to display dialog "Job finished" but not
osascript -e tell 'Application "iTerm" to display dialog "Job finished"'.
The shell is removing the outer single quotes before pb ever sees the argument(s). Pass a single argument
pb "osascript -e 'tell Application \"iTerm\" to display dialog \"Job finished\"'"
to pb, and define it as
pb () {
printf '%s\n' "$1" | pbcopy
}
It would probably be just as easy to use a here document, though, rather than define a function that feeds its argument to pbcopy:
$ pbcopy <<'EOF'
osascript -e 'tell Application "iTerm" to display dialog "Job finished"'
EOF
Slightly more typing, but no need to nest so many quotes.
Is it possible to echo a text and keep all quotes and double quotes in place? I want to write a function to copy the text currently written in the terminal (completely with quotes).
Let's explore what you mean by "currently written in the terminal". If I understand correctly, you want to provide arbitrary input to a shell command at invocation time. In other words, you have a bit of text that you want to add into your copy buffer, and you want to send it to the stdin of pbcopy to do so.
As a solution to this particular problem, a shell function is a poor fit. That's because a shell function needs to be invoked with arguments that are subject to shell interpretation, and so you'll have to escape them carefully both when invoking pb and when defining it. These strings can be escaped. But it's inconvenient, for one thing because there are several special characters that need to be escaped in a double quoted string, but ' can't itself be escaped in a single quoted string.
Let's explore some other options.
$ pbcopy <<< "this is a simple one-line string directly from the command line. Since it's an argument to pbcopy it needs to be escaped."
$ pbpaste
this is a simple one-line string directly from the command line. Since it's an argument to pbcopy it needs to be escaped.
Here we tell the shell to provide the text to pbpaste's standard input. We still have to escape the string. But we don't have to pass it anywhere or correctly enquote it again to make it a valid shell argument.
Or we can provide multi-line string data to pbcopy without having to enquote it with this special here-doc syntax:
$ pbcopy <<-'-my-chosen-delimiter'
> Since this string's delimiter is single quoted,
> no interpolation will occur. That means " double quotes
> have no meaning, nor does ' single quotes, $dollar signs
> or other such meaningful bash syntaxes.
> -my-chosen-delimiter
$ pbpaste
Since this string's delimiter is single quoted,
no interpolation will occur. That means " double quotes
have no meaning, nor does ' single quotes, $dollar signs
or other such meaningful bash syntaxes.
I have thought that bash would be more powerful than that.
Well, on one hand, I think this is a very good opportunity to compare and contrast command line arguments (which are inherently positional by design and thus must be parsed and split by, usually, whitespace between arguments) to input and output streams expressed with | pipelines. I/O streams are designed to hold arbitrary data; it's not bash's fault that you wanted to make one into a shell-parsed variable list. It's not the considerable power of bash you're observing here, it's the functional limit of your bash knowledge.
But on the other hand, you're kind of right. The concessions to the user-interactive command line interface, substantial historical constraints to achieve backwards compatibility, and many valid design considerations made bash what it is. I for one find it and its ilk to be by far the most powerful user interface to a computer. But I wouldn't use it to assemble a complex application because, frankly, it's syntactically difficult. So don't expect bash to be something it's not. If you don't want to understand it's quirky and esoteric irregularities, stick with something more recent and more pedantic like python , go , ruby, node, or whatever non unix centric people run these days:P

Bash expand variable inside osascript command

Can someone tell me how to make the variable expand in the following, please:
MESSAGE="Public IP Address has changed"
osascript -e 'tell application (path to frontmost application as text) to display \
dialog "My message is ${MESSAGE} " buttons {"OK"} with icon stop'
The single quotes are preventing variable expansion: 3.1.2.2 Single Quotes
MESSAGE="Public IP Address has changed"
osascript -e 'tell application (path to frontmost application as text) to display \
dialog "My message is '"$MESSAGE"' " buttons {"OK"} with icon stop'
# ....................^^........^^
I'm using shell string concatenation there:
a single quote to close the first part of the single quoted string,
the variable expanded within double quotes,
a single quote to open the last part of the single quoted string.

Terminal Applescript unable to escape quote

I've run into a strange problem when trying to include quote marks ' ' in my osascript command.
If I try and escape a normal escapable character, it works fine. Example: osascript -e 'tell app "Finder" to display dialog "Te\\st"' A dialog box from Finder pops up with the text Test in it.
However, the problem occurs when I try and use apostrophes when I'm writing out full sentences. Example: osascript -e 'tell app "Finder" to display dialog "Te\'st"' When I run this, all I'm left with is no dialog box, and the text input in terminal looking like this:
>
From what I know, this should by all means work, however, it doesn't.
Just to complement #Zero's helpful answer (which indeed does solve the problem):
Since you're using osascript, it is the shell's (bash's) quoting rules that apply first:
In bash (or any POSIX-compatible shell), you cannot include single quotes in a single-quoted string - not even with escaping.
What you CAN do, however, is to break your string into multiple pieces and simply splice in single quotes where needed (escaped outside a quoted string as \'):
osascript -e 'tell app "Finder" to display dialog "Te'\''st"'
'tell app "Finder" to display dialog "Te', the first part, is followed by the escaped single quote \', followed by the remainder of the string 'st"'
By virtue of having NO spaces between the parts, bash creates a single string that does contain the spliced-in literal '.
It is generally easier to pass single-quoted strings to osascript, since double quotes are frequently used in AppleScript and therefore have to be escaped when enclosed in a double-quoted string (as in the accepted answer).
In the typically infrequent event that you must pass a single quote to AppleScript, you can use the technique described in this answer.
You can do it this way:
osascript -e "tell app \"Finder\" to display dialog \"'Something' in quotes"\"

How to change directory with spaces in applescript terminal?

I'm new to applescripts and I'm trying to automate a process, but how do you change directory through the script when there are spaces inside the directory? My commands should be correct but a syntax error keeps popping up:
Expected “"” but found unknown token.
Here is my script:
tell application "Terminal"
activate
do script "cd ~/Pictures/iPhoto\ Library"
end tell
I don't understand where it is wrong. It works fine on my terminal.
Thanks a bunch guys!!
UPDATE: this worked best!!
# surround in single quotes
tell application "Terminal"
activate
do script "cd '/Users/username/Pictures/iPhoto Library'"
end tell
The are a few ways.
# escape the quotes with a backslash. AND Escape the first backslash for Applescript to accept it.
tell application "Terminal"
activate
do script "cd ~/Pictures/iPhoto\\ Library"
end tell
# surround in double quotes and escape the quotes with a backslash.
tell application "Terminal"
activate
do script "cd \"/Users/username/Pictures/iPhoto Library\""
end tell
# surround in single quotes using quoted form of
tell application "Terminal"
activate
do script "cd " & quoted form of "/Users/username/Pictures/iPhoto Library"
end tell
# surround in single quotes
tell application "Terminal"
activate
do script "cd '/Users/username/Pictures/iPhoto Library'"
end tell
Also I do not thing the tild will expand when you use the quotes on the whole path.
So you will need to get the user name another way.
Examples:
# inserting the user name. And surrond in brackets so the name and path are seen as one string before the quotes are added
set whoami to do shell script "/usr/bin/whoami"
tell application "Terminal"
activate
do script "cd /Users/" & quoted form of whoami & "/Pictures/iPhoto\\ Library"
end tell
tell application "System Events" to set whoami to name of current user
# inserting the user name. And surrond in brackets so the name and path are seen as one string before the quotes are added
tell application "Terminal"
activate
do script "cd /Users/" & quoted form of (whoami & "/Pictures/iPhoto Library")
end tell
As you can see there is more than one way to do any of this.
Or just quote the directory part.
Example.
tell application "Terminal"
activate
do script "cd ~" & quoted form of "/Pictures/iPhoto Library"
end tell

Resources