我试图在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)
我假设您的代码块正在Automator Run Shell Script操作中使用(这是一个重要的事情,包含在您的问题中,以供将来参考)。根据这个假设来解决您的特定查询,有两个关于bash和AppleScript中的变量的小花絮:
$my_command
变量作为osascript
的参数)和命令替换(其中变量的使用方式与参数的变量类似,除了它包含一个shell命令),并执行一个称为单词拆分的东西。顾名思义,它将文本拆分为单词,但在shell脚本编写的上下文中,单词由$IFS
环境变量定义的任何字符分隔。如果你特别感兴趣的话,你可以自己阅读更多内容,但是你在脚本中的作用是你从一个叫做分词的东西中预测的:它在空格中分割"cd /"
,并为每个单词提供两个单独的字段,因此将两个参数传递给osascript
,而不是你想要的那个参数。run
处理程序的参数可以用两种通用语法形式定义。首先是:
on run args
其中args
是一个变量,它将填充一个非特定数量的参数(可能为零)传递给它并生成一个list
对象,其中列表中的每个item
都是参数之一(顺序被保留)。
第二种语法形式将大括号内的变量标识符包含在内,以声明固定数量参数的列表:
on run {arg}
这里,{arg}
是一个单项list
对象,定义了精确数量的参数(在本例中为1),它将被传递给变量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
对象作为其直接参数,而它期望一个text
(string
)对象。
我可能选择修复这个特定问题的方法是防止bash中的单词拆分。这样做的方法是将参数括在双引号中:
osascript -e 'on run my_command' ... -e 'end run' "$my_command"
双引号告诉shell将内部的所有内容都视为一个单词,因此现在AppleScript变量my_command
会收到一个参数。这在技术上仍然是一个包含一个项目的列表,但是大多数期望text
对象的命令在接收包含字符串的单项列表时能够表现得很明智。
然后,正如@ user3439894在评论中指出的那样,你应该用do shell script
替换do script
,它将在新的终端选项卡/窗口中执行命令"cd /"
。
实现此修复程序的调整后的脚本可能如下所示:
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"
总而言之,在这种情况下,使用Run AppleScript操作更为明智,如下所示:
on run {my_command, null}
tell application "Terminal"
do script my_command
activate
end tell
end run
在这里,我宣布run
处理程序只传递两个参数:
第二个是Automator特有的东西,它通常有一些代码,可以将第二个参数存储在名为parameters
的变量中。这个论点由Automator传递,所以你不必担心它来自何处。它包含与此脚本实例的运行相关的本地目录信息。它在我遇到的任何情况下都不是特别有用,当然也不是在这个情况下。我更喜欢通过将第二个参数声明为null
来销毁信息。
这给我们留下了一个参数,但是这个参数将以list
的形式出现,我建议在开始之前,在您决定要更复杂之前 - 限制单个项目,这将是一个包含您的项目的字符串bash表达。
这可以通过之前的任何操作提供给Run AppleScript操作,我建议使用纯文本;一个Automator变量;或者特定于参数性质的东西(在这种情况下,一个目录,建议Finder操作是合适的)。由于您希望保持目录动态,因此获取选定查找器项将是如何向Finmat路径提供Automator并将其作为传递给AppleScript的参数的一个示例。
因此,我将做一些小改动,首先将cd
命令引入AppleScript,以避免您不得不混淆其他Automator操作,并找出如何正确组合它们。我还要修改run
处理程序参数表达式:
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
此工作流现在接收您在Finder中选择的文件,文件夹或项目的文件路径,并打开终端窗口,将其工作目录指向包含所选文件的文件夹。
它绝不是说明这个的完美实现(并且,从表面上看,macOS有一个内置服务来打开指向Finder中当前打开文件夹的终端窗口)。但是,对于与shell通信的5行AppleScript代码块,它是可行的。
这个参数声明的漂亮和狂野的表达式:
on run {{filepath}, null}
在filepath
参数周围添加了花括号,从而将其限制为一个一元文件路径参数。它消除了不必担心所做的多个选择会发生什么,因为只有选择中的第一个项目被存储。这意味着选择没有项目并触发脚本将引发错误,但如果删除大括号(抛出错误的多个选择)则反之亦然。
有很多方法可以快乐地管理所有场景,但是这个答案将超出最初的预期范围。