【问题标题】:Bash scripts extremely slow to start on OSXBash 脚本在 OSX 上启动速度极慢
【发布时间】:2017-08-16 14:51:29
【问题描述】:

我遇到了一个问题,我的 bash 脚本需要很长时间才能启动。起初我认为这是脚本本身的问题,但一个快速的实验证明了这一点。

这是示例脚本

#!/bin/bash
echo 'ping'

当我运行它时

$ time ./script.sh

我明白了

ping

real    0m12.018s
user    0m0.002s
sys    0m0.002s

(我什至看到它长达 17 秒......)令人难以置信的是,当我第二次运行它时,它立即运行。

ping

real    0m0.004s
user    0m0.002s
sys 0m0.002s

但是当我再次编辑文件时,又是漫长的等待。

$ echo 'echo test' >> gbr.sh
$ time ./gbr.sh
ping
test

real    0m13.021s
user    0m0.003s
sys 0m0.003s

这几乎就像 bash 正在编译我的脚本或其他东西。 有什么方法可以调试这个吗?我的.bash_profile 似乎也没有任何问题 - 如果我只是在.bash_profile 的第一行添加一个回显,我仍然只能在之后看到10 多秒。

我已经在 iTerm2 和本地终端中尝试过这个 - 两者都有完全相同的问题。这是在 macOS Sierra 上 - 10.12.3

【问题讨论】:

  • dtrace 是我在这里使用的工具。实际上,dtruss 可能就足够了。
  • (不,没有任何编译过程。是的,可以有脚本即使在非交互式 shell 启动时也可以自行运行,但这是正常/记录的方式是将这样一个脚本的名称放在环境变量BASH_ENV 中,所以如果没有设置,那么你就没有以文档/正确的方式挂钩)。
  • ...顺便说一下,这对我来说很像反恶意软件/系统监控产品在做它的事情(即计算脚本的哈希,将哈希发送到远程服务并得到答复)。如果是这样,您应该不仅在 bash 中看到相同的行为,而且在 any 解释的脚本(以 #!/usr/bin/awk -f 等开头的脚本等)中看到相同的行为。
  • time bash -c exit 需要多长时间?
  • 也许您的系统在检索ping 二进制路径时由于某种原因出现延迟。我以前在 macOS 中看到过这种行为。尝试使用ping 二进制文件的直接路径,并检查它是否有效。 ping 二进制完整路径是:/sbin/ping

标签: bash macos


【解决方案1】:

我在运行 macOS Sierra 10.12.5 和 10.12.6 的工作机器上遇到了同样的问题,我确认 @charles-duffy 是正确的。我公司的反恶意软件是问题所在。他们正在使用 Carbon Black 的名为 Confer 的守护程序来确保端点安全。

运行此命令查看问题是否停止:

launchctl unload /Library/LaunchDaemons/com.confer.sensor.daemon.plist

我认为 Confer 正在对它看到的每个新程序进行指纹识别,并尝试在允许它运行之前将其与黑名单进行比较。看起来它在一秒钟后超时(尝试在线注册指纹?),并且有些东西让它一遍又一遍地尝试,产生更长的整数秒延迟。这使得新修改的程序启动缓慢,但在指纹采集后速度恢复正常。


示例运行

这是我的工作笔记本电脑上出现的问题。随着时间的推移,有时延迟会增加,但每次总是增加整数秒。如果Confer记得之前的程序,就不会有延迟了。

bash 脚本

$ bash --norc --noprofile -l  # make sure rc scripts don't interfere

bash-3.2$ echo exit > exit.sh && chmod +x exit.sh

bash-3.2$ time ./exit.sh

real    0m1.004s
user    0m0.001s
sys 0m0.002s

bash-3.2$ time ./exit.sh

real    0m0.002s
user    0m0.001s
sys 0m0.001s

运行提供给bash -c的命令没有问题:

bash-3.2$ time bash -c exit

real    0m0.008s
user    0m0.002s
sys 0m0.003s

awk 脚本

但问题确实影响了 awk 脚本:

bash-3.2$ printf '%s\n' '#!/usr/bin/env awk -f' 'BEGIN { exit 0; }' > test.awk && chmod +x test.awk

bash-3.2$ time ./test.awk

real    0m4.010s
user    0m0.002s
sys 0m0.001s

bash-3.2$ time ./test.awk

real    0m0.005s
user    0m0.002s
sys 0m0.001s

编译的二进制文件

它甚至影响编译后的 C 和 Golang 代码:

bash-3.2$ printf '%s\n' '#include "stdio.h"' 'int main() {' 'printf("Hello, world!\n");' 'return 0;' '}' > hello.c && gcc -o hello hello.c

bash-3.2$ time ./hello
Hello, world!

real    0m4.006s
user    0m0.001s
sys 0m0.001s

bash-3.2$ time ./hello
Hello, world!

real    0m0.004s
user    0m0.001s
sys 0m0.001s

bash-3.2$ printf '%s\n' 'package main' 'import "fmt"' 'func main() {' 'fmt.Println("test")' '}' > test.go && go build -o test ./test.go

bash-3.2$ time ./test
test

real    0m4.018s
user    0m0.001s
sys 0m0.003s

bash-3.2$ time ./test
test

real    0m0.005s
user    0m0.001s
sys 0m0.002s

【讨论】:

  • 嘿——很高兴听到我的 WAG 被证明是准确的。顺便说一句,我建议 printf '%s\n' 'package main' 'import "fmt"' 'func main() { fmt.Println("test") }' 作为发出多行的更易读的方式。
  • 顺便说一句,通常这些工具可以配置为在非阻塞模式下运行,它们让代码在未知情况下运行并在事后做出决定。这可能会在性能影响和支持公司安全措施之间提供更合理的媒介,而不是完全卸载/禁用守护程序。
【解决方案2】:

从 10.15 开始,每次执行新脚本时,macOS 可能实际上都在与 Apple 对话。我在recent changelog for TextMate 中找到了这个:

已修复:在 macOS 10.15 上重新执行(捆绑)命令时出现延迟。 从 macOS 10.15 开始,Apple 将在每次新的 执行脚本/二进制文件,这可能会有超过一个延迟 其次,取决于互联网连接/位置。结果好像 要按 inode 缓存,以前 TextMate 会使用临时文件 执行脚本或 shell 命令时(给它们一个新的 inode 每次运行),它现在重新使用这些文件以避免重复延迟 处决。

【讨论】:

  • 有没有办法禁用这个“回电”?有些人可能不喜欢 Apple 如此随意地监视他们..
猜你喜欢
  • 1970-01-01
  • 2021-02-05
  • 2012-06-18
  • 2019-09-30
  • 1970-01-01
  • 2015-07-22
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
相关资源
最近更新 更多