我正在尝试在automator中制作脚本以使一些Shell脚本自动化。我希望文件夹位置是动态的。我设法将变量从bash传递到applescript,但是applescript给出了类型错误(-1700)“无法将类型转换为文本”。我在这里想念什么?
x="/"
my_command="cd $x"
osascript -e 'on run my_command' -e \
'tell application "Terminal"
do shell script my_command
activate
end tell' -e 'end run' $my_command
这里的命令('cd /')将不会运行,并且显示以下类型错误。
47:67: execution error: Terminal got an error: Can’t make {"cd", "/"} into type text. (-1700)
答案 0 :(得分:0)
我假设您的代码块正在 Automator 运行Shell脚本动作中使用(这是您的问题中包含的重要内容,以备将来参考)。根据这个假设来解决您的特定查询,关于bash和AppleScript中的变量,有两个小窍门要注意:
在bash中,shell将处理参数扩展(例如,在您的最后一行中将$my_command
变量用作osascript
的参数)脚本)和命令替换(其中变量的用法与参数相似,不同之处在于它包含一个shell命令),并执行称为 word splitting 的操作。顾名思义,它可以将文本拆分为单词,尽管在shell脚本编写的上下文中, word 由$IFS
环境变量定义的任何字符分隔。如果您特别感兴趣,可以自己了解更多,但这在脚本中的作用是您根据 word splitting 的预测:在空白处将"cd /"
拆分,并为每个单词提供两个单独的字段,从而将两个参数传递给osascript
,而不是您想要的一个参数。
在AppleScript中,可以用两种常规语法形式定义传递给run
处理程序的参数。第一个是:
on run args
其中args
是一个变量,将使用传递给它的非特定数量的参数(可能为零)填充并生成一个list
对象,其中每个item
列表中的参数之一(保留顺序)。
第二种语法形式将变量标识符括在花括号内,以声明固定数量的参数的列表:
on run {arg}
在这里,{arg}
是一个单项list
对象,定义了精确数量的参数(在本例中为一个),该参数将传递到变量arg
中。传递少于一个参数将在AppleScript中引发错误。传递更多的参数将把第一个参数存储在arg
中,其余的参数则丢弃。需要声明两个参数:
on run {_1, _2}
其中第一个参数传递给变量_1
,第二个参数传递给变量_2
(在所有这些示例中,变量名称的选择除了象征性之外没有其他意义,但是它们也是有效的AppleScript变量标识符的示例)。传递少于两个参数将引发错误;传递两个以上将破坏除前两个参数以外的所有参数。
您可以遵循相同的规则,以增加在处理程序中声明的参数数量,其一般形式为:
on run {a, b, c, ...}
请注意,此外,这些变量可以本身包含list
个对象。因此,on run {arg}
会收到一个参数(存储在变量arg
中,该参数可能是包含多个项目的列表。
考虑到两种不同语言的这两种功能,也许您会看到发生了什么:$my_command
进行参数扩展,将其分为两个参数"cd"
和"/"
,传递给osascript
; osascript
将每个单独的参数解释为item
中的list
,并发送给run
处理程序。幸运的是,您使用了第一个AppleScript run
处理程序语法来将参数声明为不确定长度的list
对象。
这允许将AppleScript变量my_command
传递给两个项目列表,即{"cd", "/"}
。如果您知道如何处理列表中的项目,这是可以接受的:在这种情况下,您希望将它们与空格分隔符连接在一起;直接的方法是这样的:
item 1 of my_command & space & item 2 of my_command --> "cd /"
由于未完成此操作,do shell script
(反正是错误的命令)收到了一个list
对象作为其直接参数,而它期望一个{{ 1}}(text
)对象。
我可能选择解决此特定问题的方法是防止单词在bash中分裂。这样做的方法是将参数用双引号引起来:
string
双引号告诉外壳程序将其中的所有内容都视为一个单词,因此AppleScript变量osascript -e 'on run my_command' ... -e 'end run' "$my_command"
现在收到一个参数。从技术上讲,这仍然是一个列表,包含一个项目,但是大多数期望my_command
对象的命令在收到包含字符串的单项列表时都能表现出合理的行为。
然后,正如@ user3439894在评论中指出的,您应将text
替换为do shell script
,它将在新的 Terminal 中执行命令do script
。标签/窗口。
实施此修复程序的调整后的脚本可能看起来像这样:
"cd /"
话虽如此,在这种情况下,使用 Run AppleScript 操作代替,这会更明智:
x="/"
my_command="cd $x"
osascript -e '
on run my_command
tell application "Terminal"
do script my_command
activate
end tell
end run' "$my_command"
在这里,我要声明on run {my_command, null}
tell application "Terminal"
do script my_command
activate
end tell
end run
处理程序正好传递两个参数:
第二个是 Automator 所特有的,通常有一些示例代码准备将第二个参数存储在名为run
的变量中。该参数由 Automator 传递,因此您不必担心它的来源。它包含与此脚本实例的运行相关的本地目录信息。在我遇到过的任何情况下,它并不是特别有用,当然在这种情况下也没有。我更喜欢通过将第二个参数声明为parameters
来破坏信息。
这仅给我们提供了一个参数,但是此参数将以null
的形式出现,我建议在您决定要提高复杂性之前一开始,限制为单个项目,该项目将是包含bash表达式的字符串。
可以通过之前执行的任何操作将其馈入运行AppleScript 操作,我建议使用纯文本格式; Automator 变量;或特定于参数性质的内容(在这种情况下,建议使用 Finder 操作的目录)。您希望保持目录的动态性,获取选定的查找器项将是如何为 Automator 和 Finder 路径提供示例,并具有成为传递给AppleScript的参数。
因此,我将作一些小改动,首先在AppleScript中引入list
命令,以免您不得不使用其他 Automator 动作,并弄清楚如何进行操作正确组合它们。我还将修改cd
处理程序参数表达式:
run
此工作流程现在会收到您在 Finder 中选择的文件,文件夹或项目的文件路径,并打开一个 Terminal 窗口,将其工作目录指向包含所选文件的文件夹。
这绝不是说明它的完美实现(而且,面对面,macOS具有内置服务,可以打开 Terminal 窗口,该窗口指向 Finder中的当前打开文件夹)。但是,对于与外壳进行通信的5行AppleScript代码块,它是可行的。
这是我的参数声明的精妙而疯狂的表达方式:
on run {{filepath}, null}
local filepath
set filepath to the POSIX path of ([filepath, "::"] as text)
tell application "Terminal"
do script "cd " & the quoted form of the filepath
activate
end tell
end run
在on run {{filepath}, null}
参数周围添加了花括号,从而将其限制为精确的一个一元文件路径参数。由于仅存储选择中的第一项,因此不必担心进行多个选择会发生什么。这意味着没有选择任何项目并触发脚本将引发错误,但是如果您删除括号(多个选择会引发错误),则情况相反。
有很多方法可以愉快地管理所有方案,但这将使答案超出了最初的意图。