【问题标题】:Passing variables from bash to applescript - can't make into type text. (-1700) Error将变量从 bash 传递到 applescript - 无法输入文本。 (-1700) 错误
【发布时间】:2019-04-17 16:48:56
【问题描述】:

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

【问题讨论】:

  • 您的错误之一是do shell script,它是 StandardAdditions 而不是终端的一部分。使用终端是:do script
  • 谢谢,我对 applescript 不太熟悉,但这确实在一定程度上改善了行为——它现在运行的是命令 cd,但不是 cd /。但是,关于创建变量,我仍然得到一个错误。你应该如何正确地将这两个部分连接成一个字符串? `
  • 你到底想做什么? Automator 的 Run Shell Script 操作将接受来自工作流的输入,因此不需要使用 shell 脚本来运行 AppleScript 来运行 shell 脚本。

标签: bash applescript automator


【解决方案1】:

我假设您的代码块正在 Automator Run Shell Script 操作中使用(这是包含在您的问题中的重要内容,以供将来参考)。根据这个假设来解决您的特定查询,关于 bash 和 AppleScript 中的变量需要注意两个小花絮:

  1. 在 bash 中,shell 将处理 参数扩展(例如您在脚本的最后一行使用 $my_command 变量作为 osascript 的参数)和 命令替换(其中变量的使用方式与参数类似,除了它包含一个shell命令),并执行称为分词的操作。顾名思义,它将文本拆分为单词,尽管在 shell 脚本的上下文中,word 由 $IFS 环境变量中定义的任何字符分隔。如果您特别感兴趣,您可以自己阅读更多内容,但是这在您的脚本中所做的是您从称为 分词 的东西中预测的内容:它在空格处拆分 "cd /",并且为每个单词提供两个单独的字段,因此将 两个 参数传递给 osascript,而不是您想要的一个参数。

  2. 在 AppleScript 中,传递给 run 处理程序的参数可以用两种通用语法形式定义。第一个是:

    on run args
    

    其中args 是一个变量,将使用传递给它的非特定数量的参数(可能为零)填充并生成一个list 对象,其中列表中的每个item 是其中之一参数(保留顺序)。

    第二种语法形式将变量标识符括在大括号内,以声明固定数量的参数列表:

    on run {arg}
    

    这里,{arg} 是一个单项list 对象,定义了精确数量的参数(在本例中为一个),这些参数将传递给变量arg。传递少于一个参数将在 AppleScript 中引发错误;传递 more 会将第一个参数存储在 arg 中,丢弃其余参数。需要声明两个参数:

    on run {_1, _2}
    

    第一个参数传递给变量_1,第二个参数传递给变量_2(所有这些例子中变量名的选择除了象征意义之外没有任何意义,但它们也是例子有效的 AppleScript 变量标识符)。传递的参数少于两个会抛出错误;传递两个以上的参数将破坏除前两个参数之外的所有参数。

    您可以遵循与增加在处理程序中声明的参数数量相同的规则,一般形式为:

    on run {a, b, c, ...}
    

    另外请注意,这些变量可以本身包含对象的list。因此,虽然on run {arg} 将接收单个参数,但存储在变量arg,该参数可能是一个包含多个项目的列表。


考虑到两种不同语言的这两个特性,也许你可以看到发生了什么:$my_command 进行了参数扩展,将其拆分为两个参数,"cd" 和 "/",然后传递给 @987654348 @; osascript 将每个单独的参数解释为 list 中的 item 以发送到 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 (@987654361 @) 对象。

我可能会选择解决此特定问题的方法是防止 bash 中的单词拆分。这样做的方法是将参数括在双引号中:

osascript -e 'on run my_command' ... -e 'end run' "$my_command"

双引号告诉 shell 把里面的所有东西都当作一个单词,所以现在 AppleScript 变量 my_command 接收一个参数。从技术上讲,这仍然是一个包含一个项目的列表,但大多数期望 text 对象的命令在收到包含字符串的单项目列表时都能够表现得更合理。

然后,正如@user3439894 在评论中指出的那样,您应该将do shell script 替换为do script,它将在新的终端选项卡/窗口中执行命令"cd /"。 p>

实现此修复的调整后脚本可能如下所示:

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 操作是合适的)。由于您希望保持目录动态,Get Selected Finder Items 将是如何向 Automator 提供 Finder 路径的一个示例,并具有成为传递给 AppleScript 的参数。

因此,我将做一些小改动,首先将 cd 命令引入 AppleScript 中,这样您就不必纠结于额外的 Automator 操作并弄清楚如何组合他们正确。我还要修改run handler参数表达式:

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 有一个内置服务来打开一个 Terminal 窗口,该窗口指向 Finder 中当前打开的文件夹em>)。但是,对于与 shell 通信的 5 行 AppleScript 代码块,它是可行的。

我的参数声明的这个漂亮而狂野的表达:

on run {{filepath}, null}

在filepath 参数周围添加了花括号,从而将其限制为一个精确的一元文件路径参数。它无需担心进行多项选择时会发生什么,因为只有选择中的第一项被存储。这意味着不选择任何项目并触发脚本会引发错误,但如果您删除大括号(多选会引发错误),则相反。

有很多方法可以愉快地管理所有场景,但这个答案会超出最初预期的范围。

【讨论】:

  • 哇,感谢您的课程和解决方案!虽然我打算稍后将其移至 automator,但我发现将其编写为普通的 shell 脚本进行调试更容易。我将尝试使用 Applescript 的示例,但我通常会尽量避免它。这种使其“自然”的想法使其易于阅读,但更难编写。
  • 这个想法是根据我当前在 Finder 中打开的文件夹制作一个行为不同的脚本(我省略了该部分,它工作正常)。最终脚本将用于备份某些文件夹。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多