【问题标题】:Using bash for loops in conjunction with embedded applescript for bash scripts结合使用 bash for 循环和嵌入式 applescript for bash 脚本
【发布时间】:2019-05-31 04:12:10
【问题描述】:

我正在尝试让 applescript 与作为我代码的一部分的 bash for 循环进行交互,以避免手动列出每个主机并为 hosts2.txt 中找到的每个主机执行单独的告诉/结束告诉块文件。

脚本的目的是在我的 Mac 上打开一个新的终端选项卡,并在每个新终端中自动启动“screen -r $HOST”,直到 hosts2.txt 文档中的主机列表结束。每个主机都列在自己的行上。

我尝试了一个全包 for 循环,没有下面显示的 applescript“重复 2 次”“结束重复”代码。它重复了 2 次,因为文本文档中仅列出了 2 个主机用于测试目的。每次我都有错误输出。

#!/bin/bash

for HOST in `cat ~/bin/hosts2.txt`
do echo $HOST
    osascript -e 'repeat 2 times
    tell application "Terminal" activate
tell application "System Events" to keystroke "t" using [command down]
tell application "Terminal" to activate
set host to $HOST
tell application "Terminal"
do shell script "screen -r " & host in front window
end tell
end repeat'
done

我期望发生的代码是使用 screen -r 为每个主机打开新终端选项卡的代码。错误输出低于此行。

dev
44:52: syntax error: Expected end of line but found command name. (-2741)
pulsar
44:52: syntax error: Expected end of line but found command name. (-2741)

【问题讨论】:

  • 非常好的问题,提供了很好的信息,做得好,谢谢。问题:您运行的是什么版本的 macOS?另外,如果您不介意,请发布您的~/bin/hosts2.txt 文件的内容。
  • hosts2.txt 仅包含以下内容: dev pulsar 各占一行。
  • 忘记回答其他问题。我正在使用 Mojave。

标签: bash applescript


【解决方案1】:

您的代码中有错字。

tell application "Terminal" activate 应该是tell application "Terminal" to activate

bash 中的单引号中的变量扩展也不起作用(单引号表示所有内容都按字面意思解释),因此单引号内的行 set host to $HOST 将不起作用。

试试这个:

#!/bin/bash

for HOST in `cat ~/bin/hosts2.txt`
do echo $HOST
  osascript -e "repeat 2 times
  tell application \"Terminal\" to activate
  tell application \"System Events\" to keystroke \"t\" using [command down]
  tell application \"Terminal\" to activate
  set host to \"$HOST\"
  tell application \"Terminal\"
  do shell script \"screen -r \" & host in front window
  end tell
  end repeat"
done

编辑:我认为实际上还有另一个问题:在applescript中将变量设置为字符串时,该字符串需要用引号引起来。所以set host to $HOST 会导致错误,因为它将$HOST(“pulsar”或“dev”)的值解释为它无法找到/执行的命令;它需要改为set host to \"$HOST\"。我在上面改了。

【讨论】:

【解决方案2】:

您可能会发现 here-doc 易于阅读且易于使用。此外,使用 while-read 循环遍历文件的行(参考:http://mywiki.wooledge.org/BashFAQ/001

while read -r host; do
    echo "$host"

    osabody=$(cat << END_OSA
      repeat 2 times
        tell application "Terminal" to activate
        tell application "System Events" to keystroke "t" using [command down]
        tell application "Terminal" to activate
        set host to "$host"
        tell application "Terminal"
          do shell script "screen -r " & host in front window
        end tell
      end repeat
END_OSA
)
    osascript -e "$osabody"
done < ~/bin/hosts2.txt

$(cat ... 命令替换的结尾括号必须在单独的行上,因为heredoc 的终止词必须是该行上的唯一字符。

【讨论】:

    【解决方案3】:

    您的脚本存在一些问题:一些问题使其无法完全运行;有些让它做错事;还有一些本来就不需要的。还有几个其他答案可以解决某些问题,但它们似乎都没有测试脚本,因为他们没有解决很多问题。

    ...对于在 hosts2.txt 文件中找到的每个主机...
    ...每个主机都列在自己的行中。

    然后这一行:

    for HOST in `cat ~/bin/hosts2.txt`
    

    不是你想要的。这将创建一个由单个单词组成的数组,而不是文件中的行。您想使用read 命令逐行读取文件。你可以用这种方式构造一个循环:

    while read -r HOST; do
        .
        .
        .
    done < ~/bin/hosts2.txt
    

    正如@entraz 已经指出的那样,您使用单引号将阻止shell 变量在您的osascript 中扩展。

    然后是 AppleScript 本身。

    我不清楚你为什么包含 repeat 循环。

    脚本的目的是在我的 Mac 上打开一个新的终端选项卡,并在每个新终端中自动启动“screen -r $HOST”,直到 hosts2.txt 文档中的主机列表结束。每个主机都列在自己的行上。 它重复了 2 次,因为文本文档中只列出了 2 个主机

    这是没有意义的,因为您实现了一个 bash 循环以便将这些行读入$HOST 变量。当然,您阅读的是文字,而不是线条,但 AppleScript repeat 令人头疼。把它收起来。

    那么你有这个:

    tell application "Terminal" activate
    tell application "System Events" to keystroke "t" using [command down]
    tell application "Terminal" to activate
    

    这大约是tell 终端activate 所需数量的无穷大倍。

    这一行:

    set host to $HOST
    

    会抛出错误有两个原因:首先,host 在 AppleScript 的标准添加中被视为属性的现有名称,因此您不能将其设置为新值;其次,$HOST 周围没有引号,因此它不会被识别为字符串。但是,这只是为了您的学习,因为我们实际上要完全摆脱这条线。

    最后:

    tell application "Terminal"
        do shell script "screen -r " & host in front window
    end tell
    

    错了。 do shell script 不是 Terminal 命令。这是属于 AppleScript 标准添加的命令。因此,如果您的代码的其余部分正常工作,并且到达此命令,Terminal 将不会执行任何操作。相反,shell 脚本会在没有实际 shell 的情况下在后台运行,所以这对您来说没有多大好处。

    你要的命令是do script

    遗憾的是,确实似乎至少在 High Sierra 中,用于在 Terminal 中创建新选项卡和窗口的 AppleScript 命令不再起作用,所以我明白了原因您使用 系统事件 以您所拥有的方式创建一个选项卡。幸运的是,这不是必需的,您的多个 activate 命令也不是必需的:do script 将自动运行 Terminal 并默认在新选项卡中执行脚本。

    因此,您需要的唯一 AppleScript 命令是:

    tell application "Terminal" to do script "screen -r $HOST"
    

    最终脚本

    综合起来,这是最终的混合脚本:

    while read -r HOST; do
        echo "$HOST"
        osascript -e "tell application \"Terminal\" to do script \"screen -r $HOST\""
    done < ~/bin/hosts2.txt
    

    或者

    如果您想从 bash 中获取循环并将其放入 AppleScript 中,您可以这样做,为此我将使用 heredoc (&lt;&lt;) 来简化引号的使用并提高可读性:

    osascript <<OSA
        property home : system attribute "HOME"
        property file : POSIX file (home & "/bin/hosts2.txt")
    
        set hosts to read my file using delimiter {return, linefeed}
    
        repeat with host in hosts
            tell application "Terminal" to do script ("screen -r " & host)
        end repeat
    OSA
    

    【讨论】:

    • 非常接近我希望脚本在您的“最终脚本”修订版中执行的操作。唯一的区别是我希望它打开新的终端选项卡而不是新窗口,这是您的修订正在做的。在我之前的代码中使用快捷键 Command+T 每次在运行“screen -r $HOST”之前打开一个新选项卡有什么建议吗?
    • 在我的终端中,它会打开一个新选项卡,这意味着这是您在应用程序本身中设置的设置。所以我会查看首选项并将其设置为打开新标签以支持 Windows。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    相关资源
    最近更新 更多