修改文件單行內容
ansible.builtin.lineinfile
?可以按行修改文件內容,一次修改一行,支持正則表達式。
選項名 | 類型 | 默認值 | 描述 |
attributes | str | null | 設置目標文件的 Linux 文件系統屬性(attribute bits),作用類似于? |
backrefs | bool | false | 使用? |
backup | bool | false | 修改文件前是否創建備份。備份文件將帶有時間戳后綴。 |
create | bool | false | 文件不存在時是否創建新文件。 |
firstmatch | bool | false | 如果為? |
group | str | null | 設置文件的屬組。 |
insertafter | str | EOF | 在匹配到的行之后插入。如果為? |
insertbefore | str | null | 在匹配到的行之前插入。如果為? |
line | str | null | 要插入或替換的行內容。 |
mode | raw | null | 設置文件權限(八進制形式,或? |
others | — | — | ansible.builtin.file ?模塊接受的所有參數在這里也同樣有效。 |
owner | str | null | 設置文件的屬主。 |
path | path | — | 必需項 ,目標文件的完整路徑。 |
regexp | str | null | 匹配要替換行的正則表達式。 |
search_string | str | null | 替代? |
selevel | str | null | SELinux context 中的 level。 |
serole | str | null | SELinux context 中的 role。 |
setype | str | null | SELinux context 中的 type。 |
seuser | str | null | SELinux context 中的 user。 |
state | str | present | 設置為? |
unsafe_writes | bool | false | 是否禁用臨時文件寫入機制(兼容某些掛載類型如 NFS)。 |
validate | str | null | 在寫入前校驗文件內容的命令(如? |
常用選項:
選項名 | 類型 | 默認值 | 描述 |
backrefs | bool | false | 使用? |
backup | bool | false | 修改文件前是否創建備份。備份文件將帶有時間戳后綴。 |
create | bool | false | 文件不存在時是否創建新文件。 |
owner | str | null | 設置文件的屬主。 |
group | str | null | 設置文件的屬組。 |
insertafter | str | EOF | 在匹配到的行之后插入。如果為? |
insertbefore | str | null | 在匹配到的行之前插入。如果為? |
line | str | null | 要插入或替換的行內容。 |
mode | raw | null | 設置文件權限(八進制形式,或? |
others | — | — | ansible.builtin.file ?模塊接受的所有參數在這里也同樣有效。 |
path | path | — | 必需項 ,目標文件的完整路徑。 |
regexp | str | null | 匹配要替換行的正則表達式。 |
search_string | str | null | 替代? |
state | str | present | 設置為? |
validate | str | null | 在寫入前校驗文件內容的命令(如? |
- name: Ensure SELinux is?set?to enforcing modeansible.builtin.lineinfile:path: /etc/selinux/configregexp:?'^SELINUX='line: SELINUX=enforcing- name: Make sure group wheel is not?in?the sudoers configurationansible.builtin.lineinfile:path: /etc/sudoersstate: absentregexp:?'^%wheel'- name: Replace a localhost entry with our ownansible.builtin.lineinfile:path: /etc/hostsregexp:?'^127\.0\.0\.1'line: 127.0.0.1 localhostowner: rootgroup: rootmode:?'0644'- name: Ensure the default Apache port is 8080ansible.builtin.lineinfile:path: /etc/httpd/conf/httpd.confregexp:?'^Listen 'insertafter:?'^#Listen 'line: Listen 8080- name: Add a line to a file?if?the file does not exist, without passing regexpansible.builtin.lineinfile:path: /tmp/testfileline: 192.168.1.99 foo.lab.net foocreate:?yes- name: Ensure the JBoss memory settings are exactly as neededansible.builtin.lineinfile:path: /opt/jboss-as/bin/standalone.confregexp:?'^(.*)Xms(\d+)m(.*)$'line:?'\1Xms${xms}m\3'backrefs:?yes- name: Validate the sudoers file before savingansible.builtin.lineinfile:path: /etc/sudoersstate: presentregexp:?'^%ADMIN ALL='line:?'%ADMIN ALL=(ALL) NOPASSWD: ALL'validate: /usr/sbin/visudo -cf %s
其他的選項都好理解,一眼就能看出來,
insertafter
?和?insertbefore
?我解釋一下,上邊有個例子用了?insertafter
,可以看到同時也使用了?regexp
,加了這個和不加是有區別的,可以看下邊的例子。
有個文件,內容如下:
[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
Listen=80
#test
#test
#test
playbook
?內容如下:
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.lineinfile:line:?"Listen=8080"#regexp: "^Listen="insertafter:?"^#Listen="path: /tmp/test
playbook
?想實現的是在?#Listen=
?后添加?Listen=8080
,但是有個特殊情況,文件可能不包含?#Listen=
。regexp
?被我注釋了,我們看下沒有?regexp
?的結果:
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
Listen=80
#test
#test
#test
Listen=8080
可以看到,結果是在最后一行添加了?Listen=8080
,恢復?/tmp/test
,在演示下加了?regexp
?的結果:
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
Listen=8080
#test
#test
#test
可以看到這回是將已有的?Listen=80
?修改為?Listen=8080
。
也就是說?
regexp
?和?insertafter
?或?insertbefore
組合使用時,能夠保證文件最后只有一個?Listen
?存在。
最后做兩個測試:
第一個
[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
Listen=80
#Listen=80
#test
#test
#test
[root@awx-1 ansible]#?cat?test.yml
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.lineinfile:line:?"Listen=8080"#regexp: "^Listen="insertafter:?"^#Listen="path: /tmp/test
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
Listen=80
#Listen=80
Listen=8080
#test
#test
#test
第二個:
[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#test
#test
#test
[root@awx-1 ansible]#?cat?test.yml
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.lineinfile:line:?"Listen=8080"regexp:?"^Listen="insertbefore:?"^#Listen="path: /tmp/test
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#test
#test
#test
Listen=8080
第二個例子里,我特意使用了?
insertbefore
?可以看到在沒有任何匹配時,只會在文件的最后進行追加。
最后總結下,regexp
?跟?insertafter
?或?insertbefore
?進行匹配時,情況如下:
-
regexp
?優先匹配,會修改?regexp
?匹配的行 -
regexp
?沒有匹配到時,按照?insertafter
?或?insertbefore
?的邏輯進行匹配和修改 -
都沒有匹配到時,在文件的最后一行追加
修改文件多行內容
ansible.builtin.blockinfile
?用于修改文件的多行內容。
說是修改,多數時候還是添加新的多行內容,這里強調一點,
ansible.builtin.blockinfile
?通過標記來查找文件中已添加的多行內容。
參數名 | 類型 | 默認值 | 描述 |
append_newline | bool | false | 如果插入? |
attributes | str | null | 用于設置文件的高級屬性(extended attributes),如? |
backup | bool | false | 在修改文件前創建備份。 |
block | str | null | 要插入的文本塊內容(多行字符串) |
create | bool | false | 如果文件不存在則創建 |
group | str | null | 設置文件的所屬組 |
insertafter | str | EOF | 插入內容到匹配行之后,或? |
insertbefore | str | null | 插入內容到匹配行之前,或? |
marker | str | # {mark} ANSIBLE MANAGED BLOCK | 控制? |
marker_begin | str | BEGIN | 自定義起始標記,用于替代? |
marker_end | str | END | 自定義結束標記,用于替代? |
mode | str | null | 設置文件權限(如? |
owner | str | null | 設置文件所有者 |
path | str | null | 目標文件路徑 |
prepend_newline | bool | false | 是否在? |
selevel | str | null | SELinux 安全級別 |
serole | str | null | SELinux 角色 |
setype | str | null | SELinux 類型 |
seuser | str | null | SELinux 用戶 |
state | str | present | 是否確保 block 存在或被刪除( |
unsafe_writes | bool | false | 繞過臨時文件機制直接寫入文件(有風險) |
validate | str | null | 應用更改前對文件進行語法驗證(如? |
常用選項:
參數名 | 類型 | 默認值 | 描述 |
append_newline | bool | false | 如果插入? |
backup | bool | false | 在修改文件前創建備份。 |
block | str | null | 要插入的文本塊內容(多行字符串) |
create | bool | false | 如果文件不存在則創建 |
group | str | null | 設置文件的所屬組 |
insertafter | str | EOF | 插入內容到匹配行之后,或? |
insertbefore | str | null | 插入內容到匹配行之前,或? |
marker | str | # {mark} ANSIBLE MANAGED BLOCK | 控制? |
marker_begin | str | BEGIN | 自定義起始標記,用于替代? |
marker_end | str | END | 自定義結束標記,用于替代? |
mode | str | null | 設置文件權限(如? |
owner | str | null | 設置文件所有者 |
path | str | null | 目標文件路徑 |
prepend_newline | bool | false | 是否在? |
state | str | present | 是否確保 block 存在或被刪除( |
validate | str | null | 應用更改前對文件進行語法驗證(如? |
- name: Insert/Update?"Match User"?configuration block?in?/etc/ssh/sshd_config prepending and appending a new lineansible.builtin.blockinfile:path: /etc/ssh/sshd_configappend_newline:?trueprepend_newline:?trueblock: |Match User ansible-agentPasswordAuthentication no- name: Insert/Update eth0 configuration stanza?in?/etc/network/interfaces(it might be better to copy files into /etc/network/interfaces.d/)ansible.builtin.blockinfile:path: /etc/network/interfacesblock: |iface eth0 inet staticaddress 192.0.2.23netmask 255.255.255.0- name: Insert/Update configuration using a?local?file and validate itansible.builtin.blockinfile:block:?"{{ lookup('ansible.builtin.file', './local/sshd_config') }}"path: /etc/ssh/sshd_configbackup:?yesvalidate: /usr/sbin/sshd -T -f %s- name: Insert/Update HTML surrounded by custom markers after <body> lineansible.builtin.blockinfile:path: /var/www/html/index.htmlmarker:?"<!-- {mark} ANSIBLE MANAGED BLOCK -->"insertafter:?"<body>"block: |<h1>Welcome to {{ ansible_hostname }}</h1><p>Last updated on {{ ansible_date_time.iso8601 }}</p>- name: Remove HTML as well as surrounding markersansible.builtin.blockinfile:path: /var/www/html/index.htmlmarker:?"<!-- {mark} ANSIBLE MANAGED BLOCK -->"block:?""- name: Add mappings to /etc/hostsansible.builtin.blockinfile:path: /etc/hostsblock: |{{ item.ip }} {{ item.name }}marker:?"# {mark} ANSIBLE MANAGED BLOCK {{ item.name }}"loop:- { name: host1, ip: 10.10.1.10 }- { name: host2, ip: 10.10.1.11 }- { name: host3, ip: 10.10.1.12 }
這里舉個例子來驗證?ansible.builtin.blockinfile
?是如何確認文本塊的:
[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test
#test
#test
[root@awx-1 ansible]#?cat?test.yml
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.blockinfile:path: /tmp/testappend_newline:?trueprepend_newline:?trueblock: |address 192.168.1.1netmask 255.255.255.0gateway 192.168.1.254insertafter:?"^#block"marker:?"# {mark} block test"marker_begin:?"one"marker_end:?"two"#state: absent
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test# one block test
address 192.168.1.1netmask 255.255.255.0
gateway 192.168.1.254
# two block test#test
#test[root@awx-1 ansible]#?cat?test.yml
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.blockinfile:path: /tmp/testappend_newline:?trueprepend_newline:?trueblock: |address 192.168.1.1netmask 255.255.255.0gateway 192.168.1.254insertafter:?"^#block"marker:?"# {mark} block test"#marker_begin: "one"#marker_end: "two"#state: absent[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test# BEGIN block test
address 192.168.1.1netmask 255.255.255.0
gateway 192.168.1.254
# END block test# one block test
address 192.168.1.1netmask 255.255.255.0
gateway 192.168.1.254
# two block test#test
#test
可以看到添加?block
?的時候會在?block
?的開頭和結尾添加一個標記(標記一般是?#
?開頭,表示注釋),通過?marker_begin
?和?marker_end
?修改標記的之后,會重新添加?block
,由此可見?block
?的管理依賴標記,所以在添加新的?block
?的時候記得保證標記的唯一性。
還有個小問題,append_newline
?可以在?block
?的末尾添加一個換行符來和舊內容分隔,但是每次刪除重新添加時都會多一個換行符:
[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test
#test
#test
[root@awx-1 ansible]#?cat?test.yml
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.blockinfile:path: /tmp/testappend_newline:?trueprepend_newline:?trueblock: |address 192.168.1.1netmask 255.255.255.0insertafter:?"^#block"#state: absent
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test# BEGIN ANSIBLE MANAGED BLOCK
address 192.168.1.1netmask 255.255.255.0
# END ANSIBLE MANAGED BLOCK#test
#test
[root@awx-1 ansible]#?cat?test.yml
---
- name:?testhosts: localhosttasks:- name: Lineinfile?testansible.builtin.blockinfile:path: /tmp/testappend_newline:?trueprepend_newline:?trueblock: |address 192.168.1.1netmask 255.255.255.0insertafter:?"^#block"state: absent
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test#test
#test
[root@awx-1 ansible]# ansible-playbook test.yml
...output omitted...[root@awx-1 ansible]#?cat?/tmp/test
#test
#test
#block test# BEGIN ANSIBLE MANAGED BLOCK
address 192.168.1.1netmask 255.255.255.0
# END ANSIBLE MANAGED BLOCK#test
#test