将 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
Terminal 到 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
不是 终端 命令。这是一个属于 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
我正在尝试让 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
Terminal 到 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
不是 终端 命令。这是一个属于 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