将变量从bash传递给applescript - 无法生成类型文本。 (-1700)错误

问题描述 投票:0回答:1

我试图在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)
bash applescript automator
1个回答
0
投票

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

  1. 在bash中,shell将处理参数扩展(例如您在脚本的最后一行使用$my_command变量作为osascript的参数)和命令替换(其中变量的使用方式与参数的变量类似,除了它包含一个shell命令),并执行一个称为单词拆分的东西。顾名思义,它将文本拆分为单词,但在shell脚本编写的上下文中,单词由$IFS环境变量定义的任何字符分隔。如果你特别感兴趣的话,你可以自己阅读更多内容,但是你在脚本中的作用是你从一个叫做分词的东西中预测的:它在空格中分割"cd /",并为每个单词提供两个单独的字段,因此将两个参数传递给osascript,而不是你想要的那个参数。
  2. 在AppleScript中,传递给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对象作为其直接参数,而它期望一个textstring)对象。

我可能选择修复这个特定问题的方法是防止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

Automator Workflow in macOS 10.13

此工作流现在接收您在Finder中选择的文件,文件夹或项目的文件路径,并打开终端窗口,将其工作目录指向包含所选文件的文件夹。

它绝不是说明这个的完美实现(并且,从表面上看,macOS有一个内置服务来打开指向Finder中当前打开文件夹的终端窗口)。但是,对于与shell通信的5行AppleScript代码块,它是可行的。

这个参数声明的漂亮和狂野的表达式:

on run {{filepath}, null}

filepath参数周围添加了花括号,从而将其限制为一个一元文件路径参数。它消除了不必担心所做的多个选择会发生什么,因为只有选择中的第一个项目被存储。这意味着选择没有项目并触发脚本将引发错误,但如果删除大括号(抛出错误的多个选择)则反之亦然。

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

© www.soinside.com 2019 - 2024. All rights reserved.