带有 do Javascript 的 Applescript 并传递了 Applescript 变量
Applescript with do Javascript and passed Applescript Variable
我编写了一个脚本,可以在我管理的网站上自动创建产品。在我的过程中,我上传了产品的 JPEG 图片,并提取了 JPEG 中标记的关键字以添加到产品信息中。在此过程中,我使用 Applescript 激活 Safari 并处理 Javascript 行代码。该行代码包含一个派生自 Applescript Shell 脚本的变量。
下面的代码
tell application "Finder"
set sourceFolder to folder POSIX file "/Users/<username>/Desktop/Upload/Temp/HighRes/"
set theFiles to files of sourceFolder
set inputPath to "/Users/<username>/Desktop/Upload/Temp/"
end tell
repeat with afile in theFiles
set filename to name of afile
set fname to text 1 thru ((offset of "." in filename) - 1) of filename
--INPUT CODE TO BE LOOPED OVER BELOW--
--Add Image Keywords from Metadata--
try
set pathVAR1 to "/Users/<username>/Desktop/Upload/Temp/HighRes/"
set pathVAR2 to pathVAR1 & filename
set myvar to do shell script "mdls -name kMDItemKeywords " & quoted form of pathVAR2
set var1 to ((offset of "(" in myvar) + 1)
set var2 to ((length of myvar) - 1)
set myKeywords to ((characters var1 thru var2 of myvar) as string)
--Inputs the Keywords from the Image Metadata--
tell application "Safari"
activate
do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = \"" & myKeywords & "\";" in current tab of window 1
end tell
end try
--END OF CODE TO BE LOOPED OVER--
end repeat
==结束代码==
问题:
下面的代码没有将变量 myKeywords 传递给 Safari,但是如果我 运行 一个对话框,它将出现在对话框中。
do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = \"" & myKeywords & "\";" in current tab of window 1
我没有一定能解决您问题的特定解决方案,但我确实对您的脚本有很多观察,并就如何更改脚本以提高其速度、稳健性和遵守原则提出了建议最佳实践。
去掉那个 try
块。 如果你屏蔽不必要的错误 error-catching。唯一需要包含在 try...end try
中的行是 do shell script
,但只有在您知道您的代码正在运行时才将其放入。一般来说,只应使用 try
个块:
- 当您的脚本有可能抛出完全 可预测的 和 的错误时explainable,并且你了解错误发生的原因和条件,让你实施有效的error-handling方法;
- 在尽可能少的行代码中出现错误,留下所有不存在的代码行取决于 error-prone 语句的结果;
- 在您的脚本编写、测试和调试后,放置
try
块不再用于强制脚本在出现未知来源的不便错误后继续执行,但有一个明确的 well-defined 功能可以与您的代码协调一致,而不是违背它。
作为 AppleScript 中的一般规则,如果可以避免,请不要使用 Finder 执行文件系统操作:它很慢,并且在运行时会阻塞执行操作,这意味着您在此期间无法与 GUI 交互。请改用 系统事件 。它是一个匿名应用程序,在执行任务时不会停止其他操作;它很快,特别是在 AppleScript 和 Finder 的上下文中,并且不像 Finder 那样容易超时;它本机处理 posix 路径( 包括波浪号的 扩展),无需使用 POSIX file
进行任何强制转换; it returns alias
对象,它们是每个其他可编写脚本的应用程序都能理解的通用 class 文件对象。
有几个实例仍然需要 Finder。 系统事件 不能reveal
一个文件;它也无法为您提供 Finder 中当前选定的文件。但是让 Finder 检索 selection
作为 alias list
,然后切换到 System Events 来做此列表中的实际文件处理。
这很奇怪:
set filename to name of afile
set fname to text 1 thru ((offset of "." in filename) - 1) of filename
我是否认为 fname
仅打算保留文件名的基本文件名部分,而此操作旨在去除扩展名?这是一个很好的第一次尝试,并且在此处使用 text
而不是 characters
来逐项列出字符串的组成部分,做得很好。但是,当然,如果文件名中有多个 "."
,那么最终砍掉的不仅仅是文件扩展名,这并不少见。
安全阉割文件名末尾的一种方法是使用text item delimiters
:
set filename to the name of afile
set fname to the filename
set my text item delimiters to "."
if "." is in the filename then set fname to text items 1 thru -2 of the filename as text
然后您应该注意或在之后重置 text item delimiters
,否则稍后当您尝试将字符串连接在一起时会产生后果。
另一种不使用 text item delimiters
截断扩展名的方法是字符串扫描,您可以在其中遍历字符串中的字符,边执行操作或测试边进行操作,并获得所需的结果。它比听起来更快,并且是一种用于非常复杂的字符串搜索和操作的强大技术:
set filename to the name of afile
set fname to the filename
repeat while the last character of fname ≠ "."
set fname to text 1 thru -2 of fname
end
set fname to text 1 thru -2 of fname
您还可以检索文件的 name extension
属性,获取其长度,并从文件名末尾删除 (1 + that)
个字符。有无数种方法可以达到相同的结果。
在此特定实例中这是错误的:
set myKeywords to ((characters var1 thru var2 of myvar) as string)
characters
生成 list
,然后您必须将其连接回 string
,如果您不确定 text item delimiters
是什么,这是不安全的被设置为。因为您没有在脚本中引用它,所以它 应该 设置为空字符串,这将导致将字符连接回单词产生预期的结果。然而,情况很可能并非如此,例如,如果您执行了第一种文件扩展名阉割技术而忽略了将 text item limiters
设置回去——那么生成的字符串将在每个字母之间有一个句点。
作为 AppleScript 中的一项政策(您可以个人选择遵守或忽略),如果您先执行列表到字符串的强制操作 而不先 ,它会被一些人认为是糟糕的形式将 text item delimiters
设置为确定值。
但是你不需要在这里这样做,因为不用 characters
,而是用text
:
set myKeywords to text var1 thru var2 of myvar
你正在执行一个看起来像这样的 shell 命令:mdls -name kMDItemKeywords <file>
,然后后面的两行 AppleScript 笨拙地 try and trim off bash 数组的文本表示前后的括号。相反,您可以为 mdls
打开 -raw
标志,它通过为您剥离密钥名称来简化输出。然后将括号作为第一个和最后一个字符;但是,由于输出中也有大量空白,您不妨让 bash 为您执行所有清理工作:
mdls -raw -name kMDItemContentTypeTree <file> | grep -E -io '[^()",[:blank:]]+'
这忽略了括号、双引号、逗号和空格,因此您得到的只是一个关键字列表,每行一个,没有任何额外的负担。如果您需要逐项列出它们,您可以将变量设置为 the paragraphs of
do shell script
命令的输出,该命令将文本分成几行,将每个关键字放入一个列表中。但是这里似乎您需要文本并且不介意它是多线性的。
当我开始写这个答案时,我对导致您来到这里的具体问题的原因一无所知。在详细了解 mdls
如何格式化其输出后,我现在看到问题在于 myKeywords
字符串将包含一堆双引号,并且您已经包围了myKeywords
实体在您的 JavaScript 表达式中用双引号引起来。所有这些引号仅在 AppleScript 环境中被平等地转义一次,而不是在 JavaScript 环境中,这导致每个相邻的双引号充当 open-close 对。我 运行 在 bash 中使用类似的命令来获取值数组 (kMDContentTreeType
),然后按照 AppleScript 的方式处理文本,然后在中打开 JavaScript 控制台我的浏览器并将其粘贴以说明发生了什么:
任何红色的东西都包含在一个字符串中;因此,其他所有内容都被视为 JavaScript 标识符或对象(或者如果弄乱的引号也没有弄乱语法,然后导致未终止的字符串仍然期望最后一个引号与之配对.
我认为解决方案是使用连续符 "\"
来向后兼容旧版浏览器:因此您需要在每一行(最后一行除外)后附加一个反斜杠,和 您需要将 JavaScript 表达式中 myKeywords
值周围的一对双引号更改为一对单引号。在较新的浏览器中,您可以放弃为每一行添加连续标记的麻烦,而是将一对外部双引号替换为一对反引号 (`
):
❌'This line throws
an EOF error in
JavaScript';
✅'This line is \
processed successfully \
in JavaScript';
✅`This line is also
processed successfully
in JavaScript`;
我试过 CJK 建议的反引号 ( ` ),但这对我不起作用。提出的主要问题是 kMDItemKeywords 返回转义字符。
Heart,
Studio,
Red,
\"RF126-10.tif\",
Tree,
\"Heart Tree\",
occasion,
Farm,
birds,
\"Red Farm Studio\",
\"all occasion\",
all
我能够使用以下方法摆脱转义字符:
新代码
set myKeywords to do shell script "echo " & quoted form of myKeywords & " | tr -d '[:cntrl:]'| tr '[:upper:]' '[:lower:]' | tr -d '\"'"
JAVASCRIPT
的更新代码
--Inputs the Keywords from the Image Metadata--
tell application "Safari"
activate
do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = '" & myKeywords & "';" in current tab of window 1
end tell
结果
--> " heart, studio, red, rf126-10.tif, tree, heart tree, occasion, farm, birds, red farm studio, all occasion, all"
我编写了一个脚本,可以在我管理的网站上自动创建产品。在我的过程中,我上传了产品的 JPEG 图片,并提取了 JPEG 中标记的关键字以添加到产品信息中。在此过程中,我使用 Applescript 激活 Safari 并处理 Javascript 行代码。该行代码包含一个派生自 Applescript Shell 脚本的变量。
下面的代码
tell application "Finder"
set sourceFolder to folder POSIX file "/Users/<username>/Desktop/Upload/Temp/HighRes/"
set theFiles to files of sourceFolder
set inputPath to "/Users/<username>/Desktop/Upload/Temp/"
end tell
repeat with afile in theFiles
set filename to name of afile
set fname to text 1 thru ((offset of "." in filename) - 1) of filename
--INPUT CODE TO BE LOOPED OVER BELOW--
--Add Image Keywords from Metadata--
try
set pathVAR1 to "/Users/<username>/Desktop/Upload/Temp/HighRes/"
set pathVAR2 to pathVAR1 & filename
set myvar to do shell script "mdls -name kMDItemKeywords " & quoted form of pathVAR2
set var1 to ((offset of "(" in myvar) + 1)
set var2 to ((length of myvar) - 1)
set myKeywords to ((characters var1 thru var2 of myvar) as string)
--Inputs the Keywords from the Image Metadata--
tell application "Safari"
activate
do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = \"" & myKeywords & "\";" in current tab of window 1
end tell
end try
--END OF CODE TO BE LOOPED OVER--
end repeat
==结束代码==
问题:
下面的代码没有将变量 myKeywords 传递给 Safari,但是如果我 运行 一个对话框,它将出现在对话框中。
do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = \"" & myKeywords & "\";" in current tab of window 1
我没有一定能解决您问题的特定解决方案,但我确实对您的脚本有很多观察,并就如何更改脚本以提高其速度、稳健性和遵守原则提出了建议最佳实践。
去掉那个
try
块。 如果你屏蔽不必要的错误 error-catching。唯一需要包含在try...end try
中的行是do shell script
,但只有在您知道您的代码正在运行时才将其放入。一般来说,只应使用try
个块:- 当您的脚本有可能抛出完全 可预测的 和 的错误时explainable,并且你了解错误发生的原因和条件,让你实施有效的error-handling方法;
- 在尽可能少的行代码中出现错误,留下所有不存在的代码行取决于 error-prone 语句的结果;
- 在您的脚本编写、测试和调试后,放置
try
块不再用于强制脚本在出现未知来源的不便错误后继续执行,但有一个明确的 well-defined 功能可以与您的代码协调一致,而不是违背它。
作为 AppleScript 中的一般规则,如果可以避免,请不要使用 Finder 执行文件系统操作:它很慢,并且在运行时会阻塞执行操作,这意味着您在此期间无法与 GUI 交互。请改用 系统事件 。它是一个匿名应用程序,在执行任务时不会停止其他操作;它很快,特别是在 AppleScript 和 Finder 的上下文中,并且不像 Finder 那样容易超时;它本机处理 posix 路径( 包括波浪号的 扩展),无需使用
POSIX file
进行任何强制转换; it returnsalias
对象,它们是每个其他可编写脚本的应用程序都能理解的通用 class 文件对象。有几个实例仍然需要 Finder。 系统事件 不能
reveal
一个文件;它也无法为您提供 Finder 中当前选定的文件。但是让 Finder 检索selection
作为alias list
,然后切换到 System Events 来做此列表中的实际文件处理。这很奇怪:
set filename to name of afile set fname to text 1 thru ((offset of "." in filename) - 1) of filename
我是否认为
fname
仅打算保留文件名的基本文件名部分,而此操作旨在去除扩展名?这是一个很好的第一次尝试,并且在此处使用text
而不是characters
来逐项列出字符串的组成部分,做得很好。但是,当然,如果文件名中有多个"."
,那么最终砍掉的不仅仅是文件扩展名,这并不少见。安全阉割文件名末尾的一种方法是使用
text item delimiters
:set filename to the name of afile set fname to the filename set my text item delimiters to "." if "." is in the filename then set fname to text items 1 thru -2 of the filename as text
然后您应该注意或在之后重置
text item delimiters
,否则稍后当您尝试将字符串连接在一起时会产生后果。另一种不使用
text item delimiters
截断扩展名的方法是字符串扫描,您可以在其中遍历字符串中的字符,边执行操作或测试边进行操作,并获得所需的结果。它比听起来更快,并且是一种用于非常复杂的字符串搜索和操作的强大技术:set filename to the name of afile set fname to the filename repeat while the last character of fname ≠ "." set fname to text 1 thru -2 of fname end set fname to text 1 thru -2 of fname
您还可以检索文件的
name extension
属性,获取其长度,并从文件名末尾删除(1 + that)
个字符。有无数种方法可以达到相同的结果。在此特定实例中这是错误的:
set myKeywords to ((characters var1 thru var2 of myvar) as string)
characters
生成list
,然后您必须将其连接回string
,如果您不确定text item delimiters
是什么,这是不安全的被设置为。因为您没有在脚本中引用它,所以它 应该 设置为空字符串,这将导致将字符连接回单词产生预期的结果。然而,情况很可能并非如此,例如,如果您执行了第一种文件扩展名阉割技术而忽略了将text item limiters
设置回去——那么生成的字符串将在每个字母之间有一个句点。作为 AppleScript 中的一项政策(您可以个人选择遵守或忽略),如果您先执行列表到字符串的强制操作 而不先 ,它会被一些人认为是糟糕的形式将
text item delimiters
设置为确定值。但是你不需要在这里这样做,因为不用
characters
,而是用text
:set myKeywords to text var1 thru var2 of myvar
你正在执行一个看起来像这样的 shell 命令:
mdls -name kMDItemKeywords <file>
,然后后面的两行 AppleScript 笨拙地 try and trim off bash 数组的文本表示前后的括号。相反,您可以为mdls
打开-raw
标志,它通过为您剥离密钥名称来简化输出。然后将括号作为第一个和最后一个字符;但是,由于输出中也有大量空白,您不妨让 bash 为您执行所有清理工作:mdls -raw -name kMDItemContentTypeTree <file> | grep -E -io '[^()",[:blank:]]+'
这忽略了括号、双引号、逗号和空格,因此您得到的只是一个关键字列表,每行一个,没有任何额外的负担。如果您需要逐项列出它们,您可以将变量设置为
the paragraphs of
do shell script
命令的输出,该命令将文本分成几行,将每个关键字放入一个列表中。但是这里似乎您需要文本并且不介意它是多线性的。
当我开始写这个答案时,我对导致您来到这里的具体问题的原因一无所知。在详细了解 mdls
如何格式化其输出后,我现在看到问题在于 myKeywords
字符串将包含一堆双引号,并且您已经包围了myKeywords
实体在您的 JavaScript 表达式中用双引号引起来。所有这些引号仅在 AppleScript 环境中被平等地转义一次,而不是在 JavaScript 环境中,这导致每个相邻的双引号充当 open-close 对。我 运行 在 bash 中使用类似的命令来获取值数组 (kMDContentTreeType
),然后按照 AppleScript 的方式处理文本,然后在中打开 JavaScript 控制台我的浏览器并将其粘贴以说明发生了什么:
任何红色的东西都包含在一个字符串中;因此,其他所有内容都被视为 JavaScript 标识符或对象(或者如果弄乱的引号也没有弄乱语法,然后导致未终止的字符串仍然期望最后一个引号与之配对.
我认为解决方案是使用连续符 "\"
来向后兼容旧版浏览器:因此您需要在每一行(最后一行除外)后附加一个反斜杠,和 您需要将 JavaScript 表达式中 myKeywords
值周围的一对双引号更改为一对单引号。在较新的浏览器中,您可以放弃为每一行添加连续标记的麻烦,而是将一对外部双引号替换为一对反引号 (`
):
❌'This line throws
an EOF error in
JavaScript';
✅'This line is \
processed successfully \
in JavaScript';
✅`This line is also
processed successfully
in JavaScript`;
我试过 CJK 建议的反引号 ( ` ),但这对我不起作用。提出的主要问题是 kMDItemKeywords 返回转义字符。
Heart,
Studio,
Red,
\"RF126-10.tif\",
Tree,
\"Heart Tree\",
occasion,
Farm,
birds,
\"Red Farm Studio\",
\"all occasion\",
all
我能够使用以下方法摆脱转义字符:
新代码
set myKeywords to do shell script "echo " & quoted form of myKeywords & " | tr -d '[:cntrl:]'| tr '[:upper:]' '[:lower:]' | tr -d '\"'"
JAVASCRIPT
--Inputs the Keywords from the Image Metadata--
tell application "Safari"
activate
do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = '" & myKeywords & "';" in current tab of window 1
end tell
结果
--> " heart, studio, red, rf126-10.tif, tree, heart tree, occasion, farm, birds, red farm studio, all occasion, all"