Ansible(二十七)-- ansible 中的過濾器

現在我有一個需求,我想要將獲取到的變量的值中的所有字母都變成大寫,如果想要在playbook中實現這個需求,我該怎麼辦呢?我可以藉助一個叫做"過濾器"的東西,幫助我完成剛纔的需求,"過濾器(filters)"可以幫助我們對數據進行處理,這樣解釋可能不夠直觀,不如這樣,我們先來看一個過濾器的小例子,然後結合示例解釋過濾器是個什麼東西,示例如下:

[root@server4 ~]# vim gl1.yml
[root@server4 ~]# cat gl1.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  vars:
    testvar: r1e2d3
  tasks:
  - debug:
      msg: "{{ testvar | upper }}"

如上例所示,testvar變量的值中包含三個小寫字母,在使用debug模塊輸出這個變量的值時,我們使用了一個管道符,將testvar變量傳遞給了一個名爲"upper"的東西,“upper"就是一個"過濾器”,執行上例playbook後你會發現,testvar中的所有小寫字母都被變成了大寫:在這裏插入圖片描述

通過上述示例,你一定已經明白了,過濾器是一種能夠幫助我們處理數據的工具,其實,ansible中的過濾器功能來自於jinja2模板引擎,我們可以藉助jinja2的過濾器功能在ansible中對數據進行各種處理,而上例中的upper就是一種過濾器,這個過濾器的作用就是將小寫字母變成大寫,我們可以發現,當我們想要通過過濾器處理數據時,只需要將數據通過管道符傳遞給對應的過濾器即可,當然,過濾器不只有upper,還有很多其他的過濾器,這些過濾器有些是jinja2內置的,有些是ansible特有的,如果這些過濾器都不能滿足你的需求,jinja2也支持自定義過濾器。

這篇文章我們就來總結一些常用的過濾器的用法,在總結時,不會區分它是jinja2內置的過濾器,還是ansible所獨有的,我們總結的目的是在ansible中使用這些過濾器,如果你想要了解jinja2中有哪些內置過濾器,可以參考jinja2的官網鏈接,如下

http://jinja.pocoo.org/docs/2.10/templates/#builtin-filters

一、跟字符串操作有關的過濾器

我們先來總結一些跟字符串操作有關的過濾器,示例如下:

[root@server4 ~]# vim gl2.yml
[root@server4 ~]# cat gl2.yml 
---
- hosts: testB
  remote_user: root
  vars:
    testvar: "abc123ABC 666"
    testvar1: "  abc  "
    testvar2: '123456789'
    testvar3: "1a2b,@#$%^&"
  tasks:
  - debug:
      #將字符串轉換成純大寫
      msg: "{{ testvar | upper }}"
  - debug:
      #將字符串轉換成純小寫
      msg: "{{ testvar | lower }}"
  - debug:
      #將字符串變成首字母大寫,之後所有字母純小寫
      msg: "{{ testvar | capitalize }}"
  - debug:
      #將字符串反轉
      msg: "{{ testvar | reverse }}"
  - debug:
      #返回字符串的第一個字符
      msg: "{{ testvar | first }}"
  - debug:
      #返回字符串的最後一個字符
      msg: "{{ testvar | last }}"
  - debug:
      #將字符串開頭和結尾的空格去除
      msg: "{{ testvar1 | trim }}"
  - debug:
      #將字符串放在中間,並且設置字符串的長度爲30,字符串兩邊用空格補齊30位長
      msg: "{{ testvar1 | center(width=30) }}"
  - debug:
      #返回字符串長度,length與count等效,可以寫爲count
      msg: "{{ testvar2 | length }}"
  - debug:
      #將字符串轉換成列表,每個字符作爲一個元素
      msg: "{{ testvar3 | list }}"
  - debug:
      #將字符串轉換成列表,每個字符作爲一個元素,並且隨機打亂順序
      #shuffle的字面意思爲洗牌
      msg: "{{ testvar3 | shuffle }}"
  - debug:
      #將字符串轉換成列表,每個字符作爲一個元素,並且隨機打亂順序
      #在隨機打亂順序時,將ansible_date_time.epoch的值設置爲隨機種子
      #也可以使用其他值作爲隨機種子,ansible_date_time.epoch是facts信息
      msg: "{{ testvar3 | shuffle(seed=(ansible_date_time.epoch)) }}"

在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述

二、跟數字操作有關的過濾器

跟數字操作有關的過濾器,示例如下

[root@server4 ~]# vim gl3.yml
[root@server4 ~]# cat gl3.yml 
---
- hosts: testB
  remote_user: root
  vars:
    testvar4: -1
  tasks:
  - debug:
      #將對應的值轉換成int類型
      #ansible中,字符串和整形不能直接計算,比如{{ 8+'8' }}會報錯
      #所以,我們可以把一個值爲數字的字符串轉換成整形後再做計算
      msg: "{{ 8+('8' | int) }}"
  - debug:
      #將對應的值轉換成int類型,如果無法轉換,默認返回0
      #使用int(default=6)或者int(6)時,如果無法轉換則返回指定值6
      msg: "{{ 'a' | int(default=6) }}"
  - debug:
      #將對應的值轉換成浮點型,如果無法轉換,默認返回'0.0'
      msg: "{{ '8' | float }}"
  - debug:
      #當對應的值無法被轉換成浮點型時,則返回指定值’8.88
      msg: "{{ 'a' | float(8.88) }}"
  - debug:
      #獲取對應數值的絕對值
      msg: "{{ testvar4 | abs }}"
  - debug:
      #四捨五入
      msg: "{{ 12.5 | round }}"
  - debug:
      #取小數點後五位
      msg: "{{ 3.1415926 | round(5) }}"
  - debug:
      #0100中隨機返回一個隨機數
      msg: "{{ 100 | random }}"
  - debug:
      #510中隨機返回一個隨機數
      msg: "{{ 10 | random(start=5) }}"
  - debug:
      #515中隨機返回一個隨機數,步長爲3
      #步長爲3的意思是返回的隨機數只有可能是581114中的一個
      msg: "{{ 15 | random(start=5,step=3) }}"
  - debug:
      #015中隨機返回一個隨機數,這個隨機數是5的倍數
      msg: "{{ 15 | random(step=5) }}"
  - debug:
      #015中隨機返回一個隨機數,並將ansible_date_time.epoch的值設置爲隨機種子
      #也可以使用其他值作爲隨機種子,ansible_date_time.epoch是facts信息
      #seed參數從ansible2.3版本開始可用
      msg: "{{ 15 | random(seed=(ansible_date_time.epoch)) }}"

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

三、列表操作相關的過濾器

列表操作相關的過濾器,示例如下

[root@server4 ~]# vim gl4.yml
[root@server4 ~]# cat gl4.yml 
---
- hosts: testB
  remote_user: root
  vars:
    testvar7: [22,18,5,33,27,30]
    testvar8: [1,[7,2,[15,9]],3,5]
    testvar9: [1,'b',5]
    testvar10: [1,'A','b',['QQ','wechat'],'CdEf']
    testvar11: ['abc',1,3,'a',3,'1','abc']
    testvar12: ['abc',2,'a','b','a']
  tasks:
  - debug:
      #返回列表長度,length與count等效,可以寫爲count
      msg: "{{ testvar7 | length }}"
  - debug:
      #返回列表中的第一個值
      msg: "{{ testvar7 | first }}"
  - debug:
      #返回列表中的最後一個值
      msg: "{{ testvar7 | last }}"
  - debug:
      #返回列表中最小的值
      msg: "{{ testvar7 | min }}"
  - debug:
      #返回列表中最大的值
      msg: "{{ testvar7 | max }}"
  - debug:
      #將列表升序排序輸出
      msg: "{{ testvar7 | sort }}"
  - debug:
      #將列表降序排序輸出
      msg: "{{ testvar7 | sort(reverse=true) }}"
  - debug:
      #返回純數字非嵌套列表中所有數字的和
      msg: "{{ testvar7 | sum }}"
  - debug:
      #如果列表中包含列表,那麼使用flatten可以'拉平'嵌套的列表
      #2.5版本中可用,執行如下示例後查看效果
      msg: "{{ testvar8 | flatten }}"
  - debug:
      #如果列表中嵌套了列表,那麼將第1層的嵌套列表‘拉平’
      #2.5版本中可用,執行如下示例後查看效果
      msg: "{{ testvar8 | flatten(levels=1) }}"
  - debug:
      #過濾器都是可以自由結合使用的,就好像linux命令中的管道符一樣
      #如下,取出嵌套列表中的最大值
      msg: "{{ testvar8 | flatten | max }}"
  - debug:
      #將列表中的元素合併成一個字符串
      msg: "{{ testvar9 | join }}"
  - debug:
      #將列表中的元素合併成一個字符串,每個元素之間用指定的字符隔開
      msg: "{{ testvar9 | join(' , ') }}"
  - debug:
      #從列表中隨機返回一個元素
      #對列表使用random過濾器時,不能使用start和step參數
      msg: "{{ testvar9 | random }}"
  - debug:
      #從列表中隨機返回一個元素,並將ansible_date_time.epoch的值設置爲隨機種子
      #seed參數從ansible2.3版本開始可用
      msg: "{{ testvar9 | random(seed=(ansible_date_time.epoch)) }}"
  - debug:
      #隨機打亂順序列表中元素的順序
      #shuffle的字面意思爲洗牌
      msg: "{{ testvar9 | shuffle }}"
  - debug:
      #隨機打亂順序列表中元素的順序
      #在隨機打亂順序時,將ansible_date_time.epoch的值設置爲隨機種子
      #seed參數從ansible2.3版本開始可用
      msg: "{{ testvar9 | shuffle(seed=(ansible_date_time.epoch)) }}"
  - debug:
      #將列表中的每個元素變成純大寫
      msg: "{{ testvar10 | upper }}"
  - debug:
      #將列表中的每個元素變成純小寫
      msg: "{{ testvar10 | lower }}"
  - debug:
      #去掉列表中重複的元素,重複的元素只留下一個
      msg: "{{ testvar11 | unique }}"
  - debug:
      #將兩個列表合併,重複的元素只留下一個
      #也就是求兩個列表的並集
      msg: "{{ testvar11 | union(testvar12) }}"
  - debug:
      #取出兩個列表的交集,重複的元素只留下一個
      msg: "{{ testvar11 | intersect(testvar12) }}"
  - debug:
      #取出存在於testvar11列表中,但是不存在於testvar12列表中的元素
      #去重後重復的元素只留下一個
      #換句話說就是:兩個列表的交集在列表1中的補集
      msg: "{{ testvar11 | difference(testvar12) }}"
  - debug:
      #取出兩個列表中各自獨有的元素,重複的元素只留下一個
      #即去除兩個列表的交集,剩餘的元素
      msg: "{{ testvar11 | symmetric_difference(testvar12) }}"

在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

在這裏插入圖片描述在這裏插入圖片描述

四、變量未定義時相關操作的過濾器

變量未定義時相關操作的過濾器,示例如下

[root@server4 ~]# vim gl5.yml
[root@server4 ~]# cat gl5.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  vars:
    testvar6: ''
  tasks:
  - debug:
      #如果變量沒有定義,則臨時返回一個指定的默認值
      #注:如果定義了變量,變量值爲空字符串,則會輸出空字符
      #default過濾器的別名是d
      msg: "{{ testvar5 | default('aabbcc') }}"
  - debug:
      #如果變量的值是一個空字符串或者變量沒有定義,則臨時返回一個指定的默認值
      msg: "{{ testvar6 | default('aabbcc',boolean=true) }}"
  - debug:
      #如果對應的變量未定義,則報出“Mandatory variable not defined.”錯誤,而不是報出默認錯誤
      msg: "{{ testvar5 | mandatory }}"

在這裏插入圖片描述

其實,說到上例中的default過濾器,還有一個很方便的用法,default過濾器不僅能在變量未定義時返回指定的值,還能夠讓模塊的參數變得"可有可無"。

這樣說不太容易理解,不如我們先來看一個工作場景,然後根據這個工作場景來描述所謂的"可有可無",就容易理解多了,場景如下:

假設,我現在需要在目標主機上創建幾個文件,這些文件大多數都不需要指定特定的權限,只有個別文件需要指定特定的權限,所以,在定義這些文件時,我將變量定義爲了如下樣子

Shell
  vars:
    paths:
      - path: /tmp/testfile
        mode: '0444'
      - path: /tmp/foo
      - path: /tmp/bar

如上所示,我一共定義了3個文件,只有第一個文件指定了權限,第二個文件和第三個文件沒有指定任何權限,這樣定義目的是,當這三個文件在目標主機中創建時,只有第一個文件按照指定的權限被創建,之後的兩個文件都按照操作系統的默認權限進行創建,爲了方便示例,我只定義了3個文件作爲示例,但是在實際工作中,你獲得列表中可能有幾十個這樣的文件需要被創建,這些文件中,有些文件需要特定的權限,有些不需要,所以,我們可能需要使用循環來處理這個問題,但是在使用循環時,我們會遇到另一個問題,問題就是,有的文件有mode屬性,有的文件沒有mode屬性,那麼,我們就需要對文件是否有mode屬性進行判斷,所以,你可能會編寫一個類似如下結構的

[root@server4 ~]# vim gl6.yml
[root@server4 ~]# cat gl6.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  vars:
    paths:
      - path: /tmp/test
        mode: '0444'
      - path: /tmp/foo
      - path: /tmp/bar
  tasks:
  - file: dest={{item.path}} state=touch mode={{item.mode}}
    with_items: "{{ paths }}"
    when: item.mode is defined
  - file: dest={{item.path}} state=touch
    with_items: "{{ paths }}"
    when: item.mode is undefined

在這裏插入圖片描述

[root@server3 ~]# cd /tmp/
[root@server3 tmp]# ll
total 0
-rw-r--r-- 1 root root 0 Apr  2 00:17 bar
-rw-r--r-- 1 root root 0 Apr  2 00:17 foo
-r--r--r-- 1 root root 0 Apr  2 00:16 test

上例中,使用file模塊在目標主機中創建文件,很好的解決我們的問題,但是上例中,我們一共循環了兩遍,因爲我們需要對文件是否有mode屬性進行判斷,然後根據判斷結果調整file模塊的參數設定,那麼有沒有更好的辦法呢?當然有,這個辦法就是我們剛纔所說的"可有可無",我們可以將上例playbook簡化成如下模樣:

[root@server4 ~]# vim gl6.yml
[root@server4 ~]# cat gl6.yml 
---
- hosts: testB
  remote_user: root
  gather_facts: no
  vars:
    paths:
      - path: /tmp/test
        mode: '0444'
      - path: /tmp/foo
      - path: /tmp/bar
  tasks:
  - file: dest={{item.path}} state=touch mode={{item.mode | default(omit)}}
    with_items: "{{ paths }}"

在這裏插入圖片描述

[root@server3 tmp]# rm -rf *
[root@server3 tmp]# ll
total 0
[root@server3 tmp]# ll
total 0
-rw-r--r-- 1 root root 0 Apr  2 00:20 bar
-rw-r--r-- 1 root root 0 Apr  2 00:20 foo
-r--r--r-- 1 root root 0 Apr  2 00:20 test

上例中,我們並沒有對文件是否有mode屬性進行判斷,而是直接調用了file模塊的mode參數,將mode參數的值設定爲了"{{item.mode | default(omit)}}",這是什麼意思呢?它的意思是,如果item有mode屬性,就把file模塊的mode參數的值設置爲item的mode屬性的值,如果item沒有mode屬性,file模塊就直接省略mode參數,'omit’的字面意思就是"省略",也就是說:[有就用,沒有就不用,可以有,也可以沒有],所謂的"可有可無"就是這個意思。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章