I'm just messing around with apple to script to joke with my friends. I made this simple terminal command to look like their computer is getting hacked (they scare easy). I was going to compile it into an application in apple script, but when I compile it, I keep receive a syntax error. I have tried fixing it, but to no avail. I'm just learning apple script, so this is probably a dumb rookie question. Thanks!
~Cole
Here is the script:
tell application "Terminal"
do script "while (true) do echo -n "Error: System Breach Detected 190721064281 killing proccesses. 12060219682197312-90785236412412001-612073412-712481243261=1123-0914712-1209412107381\][12389138719 End."; done"
activate
end tell
You're trying to nest a double-quoted string ("Error: System Breach...) inside another double-quoted string ("while (true) do...), but quotes don't nest. When AppleScript sees "while (true) do echo -n "Error, it thinks it's seeing a double-quoted string followed by the word Error, which doesn't make any sense.
To fix this, you can escape the inner double-quotes with backslashes (\) -- AppleScript will remove the escapes as it parses the string, so they won't get passed to the shell and confuse it. But there's another problem: you also have a stray escape (backslash) in the middle of the string, and that'll also confuse AppleScript. In order to make that work, you actually need to escape the escape (\\). Here's the result of adding the necessary escapes:
tell application "Terminal"
do script "while (true) do echo -n \"Error: System Breach Detected 190721064281 killing proccesses. 12060219682197312-90785236412412001-612073412-712481243261=1123-0914712-1209412107381\\][12389138719 End.\"; done"
activate
end tell
Related
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"
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
Salute to all devs,
Excuse me for addressing this question, but I am a little noob, when it comes to shell scripting, I am still learning (please bear with me).
Ok, long story short... I have met this shell command in someone script:
sed -e 1,\$s/a/${b} myfile > myfile_1
What does 1 stands for? and does "\" escape the character "$"?
Thank you devs.
It depends on where the line is executed.
Assuming it is executed in bash or ksh or something similar, the line means to execute sed with the script 1,$s/a/ with the contents of the shell variable b appended. Apparently, it is expected that the value of b should terminate the s instruction, otherwise sed will complain.
It's impossible to tell what the script will do without knowing the value of b -- it may simply complete the s instruction, for substituting something for a on every line, but it could contain any number of additional instructions.
This seems like it should be simple, but I'm pulling out my remaining hair trying to get it to work. In a shell script I want to run some Applescript code that defines a string, then pass that string (containing a single quote) to a shell command that calls PHP's addslashes function, to return a string with that single quote escaped properly.
Here's the code I have so far - it's returning a syntax error.
STRING=$(osascript -- - <<'EOF'
set s to "It's me"
return "['test'=>'" & (do shell script "php -r 'echo addslashes(\"" & s & "\");") & "']"
EOF)
echo -e $STRING
It's supposed to return this:
['test'=>'It\'s me']
First, when asking a question like this, please include what's happening, not just what you're trying to do. When I try this, I get:
42:99: execution error: sh: -c: line 0: unexpected EOF while looking for matchin
sh: -c: line 1: syntax error: unexpected end of file (2)
(which is actually two error messages, with one partly overwriting the other.) Is that what you're getting?
If it is, the problem is that the inner shell command you're creating has quoting issues. Take a look at the AppleScript snippet that tries to run a shell command:
do shell script "php -r 'echo addslashes(\"" & s & "\");"
Since s is set to It's me, this runs the shell command:
php -r 'echo addslashes("It's me");
Which has the problem that the apostrophe in It's me is acting as a close-quote for the string that starts 'echo .... After that, the double-quote in me"); is seen as opening a new quoted string, which doesn't get closed before the end of the "file", causing the unexpected EOF problem.
The underlying problem is that you're trying to pass a string from AppleScript to shell to php... but each of those has its own rules for parsing strings (with different ideas about how quoting and escaping work). Worse, it looks like you're doing this so you can get an escaped string (following which set of escaping rules?) to pass to something else... This way lies madness.
I'm not sure what the real goal is here, but there has to be a better way; something that doesn't involve a game of telephone with players that all speak different languages. If not, you're pretty much doomed.
BTW, there are a few other dubious shell-scripting practices in the script:
Don't use all-caps variable named in shell scripts. There are a bunch of all-caps variables that have special meanings, and if you accidentally use one of those for something else, weird results can happen.
Put double-quotes around all variable references in scripts, to avoid them getting split into multiple "words" and/or expanded as shell wildcards. For example, if the variable string was set to "['test'=>'It\'s-me']", and you happened to have files named "t" and "m" in the current directory, echo -e $string will print "m t" because those are the files that match the [] pattern.
Don't use echo with options and/or to print strings that might contain escapes, since different versions treat these things differently. Some versions, for example, will print the "-e" as part of the output string. Use printf instead. The first argument to printf is a format string that tells it how to format all of the rest of the arguments. To emulate echo -e "$string" in a more reliable form, use printf '%b\n' "$string".
To complement Gordon Davisson's helpful answer with a pragmatic solution:
Shell strings cannot contain \0 (NUL) characters, but the following sed command emulates all other escaping that PHP's (oddly named) addslashes PHP function performs (\-escaping ', " and \ instances):
string=$(osascript <<'EOF'
set s to "It's me\\you and we got 3\" of rain."
return "['test'=>'" & (do shell script "sed 's/[\"\\\\'\\'']/\\\\&/g' <<<" & quoted form of s) & "']"
EOF
)
printf '%s\n' "$string"
yields
['test'=>'It\'s me\\you and we got 3\" of rain.']
Note the use of quoted form of, which is crucial for passing a string from AppleScript to a do shell script shell command with proper quoting.
Also note how the closing here-doc delimiter, EOF, is on its own line to ensure that it is properly recognized (in Bash 3.2.57, as used on macOS 10.12, (also when called as /bin/sh, which is what do shell script does), this isn't strictly necessary, but Bash 4.x would rightfully complain about EOF) with warning: here-document at line <n> delimited by end-of-file (wanted 'EOF')
I'm trying to make this script work. It's a Bash script that is meant to take some variables, put them together and use the result to send an AppleScript command. Manually pasting the string echoed from the variable to_osa behind osascript -e to the terminal works as I want and expect it to. But when I try to combine the command osascript -e and the string to_osa, it does not work. How can I make this work?
the_url="\"http://stackoverflow.com/questions/1521462/looping-through-the-content-of-a-file-in-bash\""
the_script='tell application "Safari" to set the URL of the front document to '
delimiter="'"
to_osa=${delimiter}${the_script}${the_url}${delimiter}
echo ${to_osa}
osascript -e ${to_osa}
In addition to working manually the script also works when I write the desired command to a script and then execute it:
echo "osascript -e" $to_osa > ~/Desktop/outputfile.sh
sh ~/Desktop/outputfile.sh
String mashing executable code is error prone and evil, and there's absolutely no need for it here. It's trivial to pass arguments to an AppleScript by defining an explicit 'run' handler:
on run argv -- argv is a list of strings
-- do stuff here
end run
which you then invoke like so:
osascript -e /path/to/script arg1 arg2 ...
BTW, if your script requires a fixed number of args, you also write it like this:
on run {arg1, arg2, ...} -- each arg is a string
-- do stuff here
end run
...
Going further, you can even make the AppleScript directly executable as you would any other shell script. First, add a hashbang as follows:
#!/usr/bin/osascript
on run argv
-- do stuff here
end run
then save it in uncompiled plain text format and run chmod +x /path/to/myscript to make the file executable. You can then execute it from the shell as follows:
/path/to/myscript arg1 arg2 ...
Or, if you don't want to specify the full path every time, put the file in /usr/local/bin or some other directory that's on your shell's PATH:
myscript arg1 arg2 ...
...
So here's how you should be writing your original script:
#!/bin/sh
the_url="http://stackoverflow.com/questions/1521462/looping-through-the-content-of-a-file-in-bash"
osascript -e 'on run {theURL}' -e 'tell application "Safari" to set URL of document 1 to theURL' -e 'end run' $the_url
Quick, simple, and very robust.
--
p.s. If you'd rather open a URL in a new window rather than an existing one, see the manpage for OS X's open tool.
As a general rule, don't put double-quotes in the variable, put them around the variable. In this case it's more complicated, since you have some double-quotes for bash-level quoting, and some for AppleScript-level quoting; in this case, the AppleScript-level quotes go in the variable, the bash-level quotes go around the variable:
the_url="\"http://stackoverflow.com/questions/1521462/looping-through-the-content-of-a-file-in-bash\""
the_script='tell application "Safari" to set the URL of the front document to '
osascript -e "${the_script}${the_url}"
BTW, using echo to check things like this is highly misleading. echo is telling you what's in the variable, not what'll be executed when you reference the variable on a command line. The biggest difference is that echo prints its arguments after they've been through bash parsing (quote and escape removal, etc), but when you say "Manually pasting the string ... works" you're saying it's what you want before parsing. If the quotes are there in the echoed string, that means bash didn't recognize them as quotes and remove them. Compare:
string='"quoted string"'
echo $string # prints the string with double-quotes around it because bash doesnt't recognize them in a variable
echo "quoted string" # prints *without* quotes because bash recognizes and removes them