zoukankan      html  css  js  c++  java
  • 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 的功能是把之前的生成结果当成参数传给后面的命令,这样就不会有$()的回调地狱了。

    内部服务器,通过。

    云服务器,通过。

    搞定。

  • 相关阅读:
    linux 短信收发
    sama5d3 环境检测 adc测试
    【Codeforces 723C】Polycarp at the Radio 贪心
    【Codeforces 723B】Text Document Analysis 模拟
    【USACO 2.2】Preface Numbering (找规律)
    【Codeforces 722C】Destroying Array (数据结构、set)
    【USACO 2.1】Hamming Codes
    【USACO 2.1】Healthy Holsteins
    【USACO 2.1】Sorting A Three-Valued Sequence
    【USACO 2.1】Ordered Fractions
  • 原文地址:https://www.cnblogs.com/shining77/p/13890544.html
Copyright © 2011-2022 走看看