专栏首页数据之美Shell 黑科技之匿名函数实现任务并行化

Shell 黑科技之匿名函数实现任务并行化

shell 作为一门系统级别胶水语言,学习成本低,用起来很方便,但是缺点也显而易见:性能问题一直为人锁诟病。所以 shell 也就多用在简单的系统管理等场合,数据处理等等要求比较高的场合一般会选择 java、Python 等功能更强大、性能更好的语言。

最近用shell写了一个小函数,用来在集群间批量执行命令并返回结果:

for ip in ips
do
    ssh work@$ip "echo 1; exit" 2>/dev/null
done

执行下来功能没啥问题,但是性能却一塌糊涂,6台机器执行将近 5s,因为这个 for 循环 ssh 的过程是串行的。

那咱们有没有优化的方案呢?

首先想到的是不依赖任何三方工具或库(实际上我们 RD 也没有权限安装),有没有比较方便的办法。当然有了,每个 ssh 起来放后台不就行了吗?  嗯,说干就干,撸起袖子立马上:

ssh work@$ip "echo 1; exit" > a.txt 2>/dev/null &
...
wait

其实就是最后加了个 & 放后台执行, 嗯执行起来速度确实快了,但是。。。 会出现副作用,会显示类似任务后台执行信息:

work@zz_console 20:24:39 ~ >
echo 1 &
[1] 13013
1
work@zz_console 20:24:44 ~ >

[1]+  Done                    echo 1
work@zz_console 20:24:44 ~ >

重定向都无济于事。怎么办?为了消除这些信息,自然又想到了子进程 () :

Jun@VAIO 10.252.182.238 19:48:28 ~ >
(echo 1 &)
1
Jun@VAIO 10.252.182.238 20:28:13 ~ >

提示信息看起来完美解决了,但是新的问题又出来了:无法用 wait 等待后台进程执行完毕之后主进程再继续执行。这个问题怎么解决呢?  从 superuser 上的答案来看,又提到了新的思路:

set +m:  +m  Job control is closed.            

但是实际试了下也不行,只能隐去最后一条 Done 的完成信息,初始的信息并不会隐去:

Jun@VAIO 10.252.182.238 20:37:02 ~ >
set +m
Jun@VAIO 10.252.182.238 20:39:52 ~ >
echo 1 &
[1] 3148
Jun@VAIO 10.252.182.238 20:39:57 ~ >
1

Jun@VAIO 10.252.182.238 20:39:58 ~ >

最后 stackoverflow 有人给了个不错的思路:用函数即可解决,因为当前后台任务的提示信息只会在当前shell显示,而函数 {} 创建了子shell/bash,所以不会在当前shell显示提示信息。

function a {
    echo "I'm background task $1"
    sleep 5
}

function b {
    for i in {1..10}; do
        a $i &
    done
    wait
} 2>/dev/null

$ b
I'm background task 1
I'm background task 3
I'm background task 2
I'm background task 4
I'm background task 6
I'm background task 7
I'm background task 5
I'm background task 9
I'm background task 8
I'm background task 10

#And there's a delay of 5 seconds before I get my prompt back.

不过我实际试了下,仅用函数其实并不能完美的解决上述后台等待和副作用的问题,我这里最终用 {} 做匿名函数创建子shell的方式完美的解决了这个问题,让提示信息不在当前shell 显示,并且能用wait等待。最终代码如下:

zzcmd(){
    start_time=`date +%s`
    c=0
    [[ $1 == "" || $2 == "" ]] && cmd_usage && return
    ips="`echo \"$1\"|grep -Po '((\d{1,3}.){3}\d{1,3})'`"
    [[ $ips == "" ]] && ips="$(eval echo \"\$$1\")"
    [[ $ips == "" ]] && ips="`cat $1`"
    set +m
    nanoseconds=`date +%N`
    for ip in $ips
    do
        [[ $ip == "" || $ip == " " || ! $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && redEcho "$ip ip invalid..." && continue
        { timeout 15 ssh work@$ip "echo -e \"\e[41;37;1m ------------------- ${ip} -------------------\e[0m\n\";$2; exit" > ${nanoseconds}_$ip & } 2>/dev/null
        ((c++))
    done
    wait
    cat ${nanoseconds}_*
    rm -f ${nanoseconds}_*
    set -m
    end_time=`date +%s`
    cost_time=$(($end_time-$start_time))
    #cost_time_pretty=`date -d@$cost_time +%M"min"%S`
    greenEcho "******************* 本次执行 $c 台机器,耗时 ${cost_time}s *******************"
}

总结:

解决问题的关键在于 {} 和 () 的区别,外加 set +m:

  • {} 是匿名函数,创建了子 shell 来执行命令
  • () 是在当前shell下创建了子进程来执行命令
  • set +m 关闭后台任务控制信息显示

后记:

当然了也有很多第三方的工具和库也可以解决这个问题,比如 Ansible、puppet 等自动化运维管理工具,还有GNU的paralle程序等,但都没有这个方便和易于理解。

Refer:

[1] Running bash commands in the background without printing job and process ids

https://stackoverflow.com/questions/7686989/running-bash-commands-in-the-background-without-printing-job-and-process-ids

[2] Preventing bash from displaying “Done” when a background command finishes executing

https://superuser.com/questions/305933/preventing-bash-from-displaying-done-when-a-background-command-finishes-execut

[3] Bash脚本实现批量作业并行化

http://bit.ly/2qZ8CZV

[4] GNU Parallel指南

https://my.oschina.net/enyo/blog/271612

[5] GNU parallel

http://about.uuspider.com/2015/09/22/parallel.html

[6] GNU Parallel

http://www.voidcn.com/blog/huozhanfeng/article/p-3006344.html

[7] 如何利用多核CPU来加速你的Linux命令 — awk, sed, bzip2, grep, wc等

http://www.vaikan.com/use-multiple-cpu-cores-with-your-linux-commands/

[8] Bash脚本15分钟进阶教程

http://www.vaikan.com/bash-scripting/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python编写渗透工具学习笔记二 | 0x02利用FTP与web批量抓肉鸡

    0x02利用FTP与web批量抓肉鸡 脚本要实现的目标和思路: 先尝试匿名登录ftp,当匿名登录失败时再尝试用用户/密码爆破登录,登录成功后,脚本会搜索ftp中...

    安恒网络空间安全讲武堂
  • 【HTB系列】靶机Access的渗透测试详解

    Hack The Box是一个CTF挑战靶机平台,在线渗透测试平台。它能帮助你提升渗透测试技能和黑盒测试技能,它包含了一些不断更新的挑战,其中有模拟真实世界场景...

    Ms08067安全实验室
  • 1分钟链圈 | 区块链工程师,年薪最低约为10.5万美元!虾米音乐创始人吴轶群:要做全球前五的公链

    这里是 7 月 19 日的每日1句话新闻晚报,只需1分钟,看看全球最热、最新的区块链新闻。

    区块链大本营
  • 日媒揭暗网:用虚拟货币结算 已成网络黑市犯罪温床

    环球网综合报道,《日本经济新闻》7月12日报道称,互联网空间存在着即使通过百度、谷歌和雅虎等进行搜索也不会显示的网站。这些网站被称为“暗网(Dark Web)”...

    C4rpeDime
  • 重磅 | MIT AI 实验室发布16大年度黑科技:神经网络与机器人最前沿

    【新智元导读】MIT人工智能实验室( CSAIL )近日在官网刊文,回顾了实验室在过去一年所取得的技术突破。他们在机器人、计算机视觉、神经网络等方面取得了瞩目的...

    新智元
  • 川普大帝被攻击,黑客却坐不住了

    9 月 5 日纽约时报的一篇匿名文章《我是川普政府中的一名抵抗者》像一枚深水炸弹,激起了千层浪。

    HyperAI超神经
  • 一文详解Webshell

    Webshell是黑客经常使用的一种恶意脚本,其目的是获得对服务器的执行操作权限,比如执行系统命令、窃取用户数据、删除web页面、修改主页等,其危害不言而喻。黑...

    FB客服
  • SSH僵尸主机挖矿木马预警

    XMR(门罗币)是目前比特币等电子货币的一种,以其匿名性,支持CPU挖矿,以及不菲的价格等特点,得到了“黑产”的青睐。瀚思科技挖掘出黑产利用互联网服务器进行挖矿...

    FB客服
  • Android跨进程通信IPC之1——Linux基础

    由于Android系统是基于Linux系统的,所以有必要简单的介绍下Linux的跨进程通信,对大家后续了解Android的跨进程通信是有帮助的,本篇的主要内容如...

    隔壁老李头

扫码关注云+社区

领取腾讯云代金券