将变量从bash传递到applescript-无法输入文字。 (-1700)错误

时间:2019-04-16 13:10:10

标签: bash applescript automator

我正在尝试在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)

1 个答案:

答案 0 :(得分:0)

我假设您的代码块正在 Automator 运行Shell脚本动作中使用(这是您的问题中包含的重要内容,以备将来参考)。根据这个假设来解决您的特定查询,关于bash和AppleScript中的变量,有两个小窍门要注意:

  1. 在bash中,shell将处理参数扩展(例如,在您的最后一行中将$my_command变量用作osascript的参数)脚本)和命令替换(其中变量的用法与参数相似,不同之处在于它包含一个shell命令),并执行称为 word splitting 的操作。顾名思义,它可以将文本拆分为单词,尽管在shell脚本编写的上下文中, word $IFS环境变量定义的任何字符分隔。如果您特别感兴趣,可以自己了解更多,但这在脚本中的作用是您根据 word splitting 的预测:在空白处将"cd /"拆分,并为每个单词提供两个单独的字段,从而将两个参数传递给osascript,而不是您想要的一个参数。

  2. 在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""/",传递给osascriptosascript将每个单独的参数解释为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

Automator Workflow in macOS 10.13

此工作流程现在会收到您在 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} 参数周围添加了花括号,从而将其限制为精确的一个一元文件路径参数。由于仅存储选择中的第一项,因此不必担心进行多个选择会发生什么。这意味着没有选择任何项目并触发脚本将引发错误,但是如果您删除括号(多个选择会引发错误),则情况相反。

有很多方法可以愉快地管理所有方案,但这将使答案超出了最初的意图。