将 bash for 循环与 bash 脚本的嵌入式 applescript 结合使用

Using bash for loops in conjunction with embedded applescript for bash scripts

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

该脚本的目的是在我的 Mac 上打开一个新的终端选项卡并在每个新终端中自动启动 "screen -r $HOST" 直到 [=26= 中的主机列表结束] 文档。每个主机都在其自己的行中列出。

我已经尝试了一个全包 for 循环,没有下面显示的 applescript "repeat 2 times" "end repeat" 代码。它重复了 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

我期望发生的是代码执行打开新的终端选项卡,屏幕 -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)

您的代码有错别字。

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")的值解释为它无法 find/execute 的命令;它需要 set host to \"$HOST\" 代替。我已经在上面更改了。

您可能会发现 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 的终止词 必须 是该行中唯一的字符。

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

...for each host found in the hosts2.txt file...
...Each host is listed on its own line.

然后这一行:

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

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

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

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

中扩展

然后是 AppleScript 本身。

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

The purpose of the script is to open a new terminal tab on my Mac and automatically launch "screen -r $HOST" in each new terminal until the end of the list of hosts in the hosts2.txt document. Each host is listed on its own line. It is repeating 2 times because there are only 2 hosts listed in the text document

这是没有意义的,因为您实现了 bash 循环以便将行读入 $HOST 变量。当然,您阅读的是文字,而不是行,但 AppleScript repeat 令人头疼。装箱。

那么你有这个:

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

这大约是 tell Terminalactivate 所需数量的无限倍。

这一行:

set host to $HOST

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

最后:

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

错了。 do shell script 不是 终端 命令。这是一个属于 AppleScript 标准添加的命令。因此,如果您的其余代码有效,并且它到达此命令,Terminal 将不执行任何操作。相反,shell 脚本会在没有实际 shell 的情况下在后台 运行,所以这对你来说不是很好。

您要执行的命令是 do script

可悲的是,确实看起来,至少在 High Sierra 中,AppleScript 命令创建新标签,windows 在 Terminal 不再有效,所以我可以理解您为什么使用 System Events 以您现有的方式创建选项卡。值得庆幸的是,这不是必需的,您的多个 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 (<<) 来简化使用引号和帮助提高可读性:

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