• bash脚本关于单引号和变量的问题


    最近在研究服务器自动部署脚本,同时也学习一下 bash 命令的运用。现在遇到并解决了一个问题,场景是这样的:

    想通过 bash 脚本自动从 coding 上下载更新脚本,更新脚本里可以从 coding 的 docker 库里拉打包好的 docker,但服务器上拉之前,要先删除原来的容器和镜像,本来是通过以下代理完成的:

    1 docker kill $(docker ps -a -q)
    2 docker rm $(docker ps -a -q)
    3 docker rmi $(docker images -a -q)

    这三句是把所有的容器和镜像全部删掉,后来通过 docker 加了 Portainer 来管理 docker 后,运行代码时并不想把 portainer 的容器及镜像也删掉,因此做了以下修改:

    docker kill $( docker ps -a -q | grep $(docker ps -f "name=portainer-test" -q))
    docker rm $( docker ps -a -q | grep $(docker ps -f "name=portainer-test" -q))
    docker rmi $( docker images -q | grep $(docker images portainer/portainer -q))

    在操作的时候,把portainer 的容器及镜像排除掉。

    后来,随着业务需求的增加,在我们的内部服务器上也准备通过这个脚本来更新,但内部服务器上还有个jenkins镜像,又对脚本进行了修改:

    1 docker kill $( docker ps -a -q | grep -E '$(docker ps -f "name=portainer-test" -q)|$(docker ps -f "name=zealous_mestorf" -q)')
    2 docker rm $( docker ps -a -q | grep -E '$(docker ps -f "name=portainer-test" -q)|$(docker ps -f "name=zealous_mestorf" -q)')
    3 docker rmi $( docker images -q | grep -E '$(docker images portainer/portainer -q)|$(docker images jenkinsci/blueocean -q)')

    先找出 portainer 和 jenkins 的容器和镜像,排除后再进行删除。

    看着这段代码,我本身十分地抗拒。这段代码十分的不优雅,完全是硬编码。虽然现在是可以用,但是如果之后还要多排除一个镜像呢?还要再加一次吗?

    后来想想,多一事不如少一事,能工作的代码就是好代码。这个脚本在内部服务器上运行成功了,之后就是把这个脚本同步到云服务器上,然后报错了。。。因为云服务器上只有 portainer 没有 jenkins。。。

    结果还是不能偷懒,经过近1小时的努力,终于现在修改成了现在这样:

     1 # join array to string. ('a' 'b') => 'a,b'
     2 join() {
     3     arr=($@)
     4     ids=${arr[*]}
     5     echo ${ids// /|}
     6 }
     7 
     8 # init ignore list
     9 ignore_containers_list=('portainer-test' 'zealous_mestorf')
    10 ignore_images_list=('portainer/portainer' 'jenkinsci/blueocean')
    11 ignore_docker_containers_list=()
    12 ignore_docker_images_list=()
    13 
    14 # get containerID
    15 for ((loop_i=0; loop_i<${#ignore_containers_list[*]}; loop_i++))
    16 do
    17     ignore_docker_containers_list[$loop_i]=$(docker ps -f "name=${ignore_containers_list[$loop_i]}" -q)
    18 done
    19 
    20 # get imageID
    21 for ((loop_i=0; loop_i<${#ignore_images_list[*]}; loop_i++))
    22 do
    23     ignore_docker_images_list[$loop_i]=$(docker images ${ignore_images_list[$loop_i]} -q)
    24 done
    25 
    26 # get ignore id string
    27 ignore_container_string=`join ${ignore_docker_containers_list[*]}`
    28 ignore_image_string=`join ${ignore_docker_images_list[*]}`
    29 
    30 # run command
    31 echo "docker ps -a -q | grep -E '[^$ignore_container_string]' | xargs docker kill" | sh 
    32 
    33 echo "docker ps -a -q | grep -E '[^$ignore_container_string]' | xargs docker rm" | sh
    34 
    35 echo "docker images -q | grep -E '[^$ignore_image_string]' | xargs docker rmi" | sh

    先是一个 join 函数,相当于 javascript 里的 join,就是把数组变成字符串,现在分隔符只有『 | 』,之后还要改成能传分隔符。

    然后是定义container 和 image 列表,由于 container 和 image 的名称各不相同,因此分为两个列表,之后有新的 docker 要排除,直接把名称放进去就行。

    再次就是从上面两个列表中把操作的 ID 提取出来,做成两个 ID 列表,然后把 ID 列表通过 join 函数变成 a|b|c 的形式,方便之后 command 调用。

    command 这里做了两处调整:

    第一处是grep -E:

    名称映射 ID 这一步已经上面完成了,因此只要排除这些 ID 即可,这里通过 grep 的正则 -E 来实现,通过[^a|b|c]来排除需要排除的 ID,那么剩下的就是可以删除的容器及镜像了。

    第二处是xargs

    本来是通过$()来做子语句查询,后来调试的时候怎么都出不来,以及之前就想把命令改成 xargs 模式来做,看着更清楚,于是就统一改成了 xargs 来做。xargs 的功能是把之前的生成结果当成参数传给后面的命令,这样就不会有$()的回调地狱了。

    内部服务器,通过。

    云服务器,通过。

    搞定。

  • 相关阅读:
    牛人读书 列表
    设计模式 简介
    java 并发编程 list
    Spring Boot 概念知识
    JS原生Date类型方法的一些冷知识
    JavaScript 操作 Cookie
    nodeJS(express4.x)+vue(vue-cli)构建前后端分离详细教程(带跨域)
    Vue学习笔记(一)
    windows下常查看端口占用方法总结
    webstorm添加*.vue文件代码提醒支持webstorm支持es6vue里支持es6写法
  • 原文地址:https://www.cnblogs.com/shining77/p/13890544.html
Copyright © 2020-2023  润新知