Weird single quote escaping by applescript

Hello,

Given :

set a to " \" "
display dialog a
display dialog quoted form of a

set a to " ' "
display dialog a
display dialog quoted form of a

The first set behaves as expected. You get :

tell application "AppleScript Editor"
	display dialog " \" "
		--> {button returned:"OK"}
	display dialog "' \" '"
		--> {button returned:"OK"}
end tell

Although the second set behaves strangely. You get :

tell application 'AppleScript Editor"
	display dialog " ' "
		--> {button returned:"OK"}
	display dialog "' '\\'' '" --> What happened here ?
		--> {button returned:"OK"}
end tell

It seems to be adding \" after the single quote for some reason.

Thoughts?

Using 10.7.2.

I don’t know what you see in Lion but in Snow Leopard it seems like expected: ’ ‘'’ ’

The initial string is a single quote => ’

I was expecting to see for the quoted form => ’ ' ’
A single escaped quote with a single quote on each side.

Not => ’ ’ ' ’ ’
A single escaped quote with two single quotes on each side.

Spaces added for clarity.

Well I don’t get it, sorry. A single quote is in AS not a special character unlike the backslash and double quote “ they have special meanings in AppleScript which means they need to be escaped if they need to behave like a normal character. Escaped characters are:

\ =
" = "
\n = newline
\r = cariage return
\t = tab

In the AppleScript environment special characters need to be escaped. When you write data to a file or show a string on the screen (outside the AppleScript environment) the escaped characters will be replaced with it’s value.

So your string “’ ‘\’’ '” is actualy “’ ‘'’ '”. You have escaped the backslash and not the single quote behind it. Like I said a single quote doesn’t have a special meaning like in PHP, Javascript or shell scripts. It’s more like a C string

ok, I understand all of that.

quoted form of aString

adds a single quote at the beginning and end of aString ?

If aString is a single quote => set aString to " ’ "

Shouldn’t the quoted form of aString be three single quotes when displayed? => ’ ’ ’

It would be ’ ’ \ ’ ’ ’ on my machine (not the spaces). Because with quoted form “ a string supposed to be used for the shell and there a single quote has a special meaning “ you’re escaping the quote in the string by saying it has no special meaning. How would the shell know if it is the end of string or a meaningless character? The quoted string form in the shell differs a little bit. You can escape a special character or quote the whole string (same as quoted form of). the first command of example below is the same as quoted form of command and the second command is an escaped string

do shell script "echo  'x'\\''x'" --result: "x'x"
do shell script "echo x\\'x" --result: "x'x"

With some experimenting I think I figured out where I was confused.

tell application "Terminal" to do script "echo " & quoted form of " x\"x " --> echo ' x"x ' --> x"x 
tell application "Terminal" to do script "echo " & quoted form of " x'x " --> echo ' x' \' 'x ' --> x'x 

My initial question was why is there a different way of parsing how it’s send to the command line.
When double quotes are used it’s sent as a single statement, but when single quotes are used it’s sent as a triple statement.

double => ’ x"x ’
single => ’ x’ and ' and 'x ’

It does this since ’ x ' x ’ does not work. Why? Good question?

Now using double quotes you can write it like above => " x " x " and that does work.
You can also write it in three parts and it still works => " x" and " and "x "
In the actual command you take out the and

I think that explains it, although it still seems rather confusing… Spaces are for clarity.

Not really, you send every command seperated by a return or ; to the interpreter. The inpterpreter receives a string and start parsing it. While parsing it you can indicate with quotes which parts belongs to eachother. Normally values on the command line are separated by characters in the input field separator, a variable named IFS. By default it contains a newline, tab and a space.

--the command line interpreter sends hello and world as two seperate values to the process
set theFormat to "'arg1:%s" & return & "arg2:%s'"
do shell script "printf " & theFormat & " hello world"

I’ve used in the example above printf because echo isn’t able to show us the parameters. Now if we want hello world as a single argument to an application we need to escape it:

–the double backslash is for AppleScript needed, when it is send to the command line it’s a single backslash.

set theFormat to "'arg1:%s" & return & "arg2:%s'"
do shell script "printf " & theFormat & " hello\\ world"

The example above is also named a single character quotation. You told the interpreter that the next character is a space and not a delimiter/separator. There is also a strong quotation for the shell where hello world can be notated in many different ways.


set theFormat to "'arg1:%s" & return & "arg2:%s'"

do shell script "printf " & theFormat & " 'hello world'"
do shell script "printf " & theFormat & " \"hello world\""
do shell script "printf " & theFormat & " hello' 'world"
do shell script "printf " & theFormat & " hello\" \"world"
do shell script "printf " & theFormat & " 'hello'' 'world"
do shell script "printf " & theFormat & " \"hello\"\" \"world"
do shell script "printf " & theFormat & " 'hello'' ''world'"
do shell script "printf " & theFormat & " \"hello\"\" \"\"world\""
do shell script "printf " & theFormat & " hello' ''world'"
do shell script "printf " & theFormat & " hello\" \"\"world\""
--you can even mix single and double quotes in a string
do shell script "printf " & theFormat & " hello\" \"'world'"
do shell script "printf " & theFormat & " hello' '\"world\""
--I think this would be enough examples :D

Maybe a little to many examples but, as you can see, strong quotations does not indicate the beginning of a value nor does it indicate the end of a value. It turns on and off if the following characters are quoted or not. Then there is the quote in string

do shell script "echo x\\'x" --"x'x"
do shell script "echo \"x'x\"" --"x'x"
do shell script "echo 'x'\\''x'" --"x'x";same as quoted form of
do shell script "echo 'x'\"'\"'x'" --"x'x"
do shell script "echo 'x'\\'\"x\"" --"x'x"; the most odd one

But after all this and knowing how quotations works on the command line, quoted form of has never let me down. It has been working perfectly even when there are quoted form of quoted forms involved (like MySQL on the command line). Quoted form of is not only a solid command but also faster than inventing the wheel again with AppleScript code.

I have a droplet for acquiring the path of a media file and sending a command to the command line application, “mediainfo” by way of a .command executable file. I’m trying to understand why it fails for dropped files containing one or more apostrophes. Please tell me why, when the resulting text construct is saved as a .command file and executed by the AppleScript, Terminal sees the adjacent single quotes as '\" (single quote followed by backslash followed by double quotes) rather than '\'' (single quote followed by backslash followed by single quote followed by single quote). If I paste the resulting command into a Terminal window, it executes flawlessly. Is it because executing a .command file is too deprecated to be useful in such a case? Is there a way to apply more text transformation or document type declaration that can make the execution of the .command file effective? Thanks.

property startnum : 0
property newline : ASCII character 10
property tmpfile : "/tmp/execme.command"

on open the_items
	my mediaInfo(the_items)
end open

on mediaInfo(the_items)
	set theshellscript to ""
	repeat with the_item in the_items
		set the_item to the_item as alias
		tell application "Finder"
			set sost to (container of the_item) as string
		end tell
		set pos_filepath to POSIX path of sost
		set this_filepath to (the_item as string)
		set thesourcename to (name of (info for the_item))
		set namepart to (name extension of (info for the_item))
		set quoted_source_file to quoted form of (POSIX path of this_filepath)
		##set the clipboard to quoted_source_file
		##display dialog quoted_source_file
		##quoted form of
		set theshellscript to the theshellscript & "/opt/homebrew/bin/mediainfo" & space & quoted_source_file & space & "; echo '" & "

==========================

Media Information for" & space & "\"" & thesourcename & "\"" & "

==========================

';"
		
	end repeat
	##set the clipboard to theshellscript
	
	
	set theshellscript to theshellscript & "sleep 3;mv" & space & (quoted form of tmpfile) & space & (quoted form of (POSIX path of (path to trash)))
	do shell script "echo " & quoted form of theshellscript & " > " & tmpfile
	repeat
		do shell script "chmod +x " & tmpfile
		do shell script "open -a Terminal.app" & space & tmpfile
		exit repeat
	end repeat
	
end mediaInfo

on run
	set the_items to ((choose file) as list)
	mediaInfo(the_items)
end run

I’m not sure that this is how the script is interpreting the string. Of course, I’m not sure that it isn’t either.

But, given this example (file bb'cc.txt), what I see is this:

"'/Users/u/Desktop/bb'\\''cc.txt'"

'/Users/u/Desktop/bb'
\\'
'cc.txt'

It is splitting the string on the unbalanced apostrophe, escaping that character, and then single quoting the string segments on either side.


In the language guide, the same example appears twice; first under class reference > text and second under commands reference > choose folder.

Excerpt:

The following example gets a POSIX path to a chosen folder and uses the quoted form property (of the text class) to ensure correct quoting of the resulting string for use with shell commands:

set folderName to quoted form of POSIX path of (choose folder)

Suppose that you choose the folder named iWork '08 in your Applications folder. The previous statement would return the following result, which properly handles the embedded single quote and space characters in the folder name:

"'/Applications/iWork '\\''08/'"

Thanks, but the issue is not finding an acceptable method of escaping or quoting for a command pasted or typed into the Terminal. For example the following works fine when pasted into Terminal:

/opt/homebrew/bin/mediainfo ~'/Downloads/Dead Men Don'\''t Wear Plaid.mp4'

The issue occurs for an executable .command file which includes the above command, either by executing it with the AppleScript used to create it (such as that included in my previous reply) or by double-clicking it in Finder. You can demonstrate this yourself by creating a droplet from the AppleScript source, then dropping a media file on it. If the dropped file’s name includes one or more “problem” characters such as apostrophe, the resulting Terminal window reports an error, but if you open the file existing in /tmp that was both created and executed by the script, then copy the first command (the part before the first “;”), then paste it into Terminal and press return, it is completed successfully. (The part of the script that moves the executable file to the trash, that is, everything from the first “;” on, fails, because it’s not applicable in the current context.)

I’m hoping to find a workaround other than simply removing the problematic characters from the target file’s name prior to execution then restoring the original name afterwards. That’s not out of the question, the workaround probably exists somewhere, perhaps I just need to find it.

I think the problem occurs when the echo command is handed off to the shell which it doesn’t seem to survive. I wonder if separating it from the rest of the pieces of theshellscript —maybe by putting it in its own variable— might enable it to make it through.

Shouldn’t it be

/opt/homebrew/bin/mediainfo ~/Downloads/Dead\ Men\ Don\'t\ Wear\ Plaid.mp4

Or


/opt/homebrew/bin/mediainfo "~/Downloads/Dead Men Don't Wear Plaid.mp4"

I suppose the question is somewhat off topic. I can certainly successfully use either the command I provided or the first of the two you provided in a Terminal window. But my question is how I may use either of those commands in a shell script command file (having the extension .command) so I can double-click it in Finder or execute it using the included AppleScript.

I did find a workaround, so I’ll need to consider rewriting the script to learn whether the workaround provides an alternative method.

I created a shell script file named exy.sh containing the following, then made it executable:

#!/usr/bin/env zsh
/opt/homebrew/bin/mediainfo ~'/Downloads/Dead Men Don'\''t Wear Plaid.mp4'

Then (after changing the present working directory in a Terminal window to the one where I had created it) I was able to execute it using:

./exy.sh

That preserved the integrity of the contained command and yielded the desired results.

Thanks.

I think I have it now. All that was really changed is that the script builds, creates and executes a shell script file rather than a .command file.

property newline : ASCII character 10
property tmpfile : "/tmp/execme.sh"

on open the_items
	my mediaInfo(the_items)
end open

on mediaInfo(the_items)
	set theshellscript to "#!/usr/bin/env zsh" & newline
	repeat with the_item in the_items
		set the_item to the_item as alias
		tell application "Finder"
			set sost to (container of the_item) as string
		end tell
		set pos_filepath to POSIX path of sost
		set this_filepath to (the_item as string)
		set thesourcename to (name of (info for the_item))
		set namepart to (name extension of (info for the_item))
		set the_source_file to (POSIX path of this_filepath)
		set theshellscript to the theshellscript & "/opt/homebrew/bin/mediainfo" & space & (quoted form of the_source_file) & newline & "echo" & space & "\"========================= Media Info finished! =========================\""
	end repeat
	set theshellscript to theshellscript & newline & "sleep 3" & newline & "mv" & space & (quoted form of tmpfile) & space & (quoted form of (POSIX path of (path to trash) & "execme.sh"))
	do shell script "echo" & space & quoted form of theshellscript & " > " & tmpfile
	repeat
		do shell script "chmod +x " & tmpfile
		do shell script "open -a Terminal.app" & space & tmpfile
		exit repeat
	end repeat
end mediaInfo

on run
	set the_items to ((choose file) as list)
	mediaInfo(the_items)
end run