只检查文件中是否存在一行(可见)

在可见的情况下,我需要检查文件中是否存在特定的行。基本上,我需要将下面的命令转换为可执行的任务。我的目标只是检查。

grep -Fxq "127.0.0.1" /tmp/my.conf
109296 次浏览

使用可变换的 lineinfile 命令,但是如果文件不存在,该命令将使用该行更新该文件。

- lineinfile: dest=/tmp/my.conf line='127.0.0.1' state=present
- name: Check whether /tmp/my.conf contains "127.0.0.1"
command: grep -Fxq "127.0.0.1" /tmp/my.conf
register: checkmyconf
check_mode: no
ignore_errors: yes
changed_when: no


- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: checkmyconf.rc == 0

更新2017-08-28: 较老的安赛尔版本需要使用 always_run: yes而不是 check_mode: no

对于已接受的解决方案,即使忽略错误,如果没有匹配,在第一个任务上仍然会得到丑陋的红色错误输出:

TASK: [Check whether /tmp/my.conf contains "127.0.0.1"] ***********************
failed: [localhost] => {"changed": false, "cmd": "grep -Fxq "127.0.0.1" /tmp/my.conf", "delta": "0:00:00.018709", "end": "2015-09-27 17:46:18.252024", "rc": 1, "start": "2015-09-27 17:46:18.233315", "stdout_lines": [], "warnings": []}
...ignoring

如果希望减少冗长的输出,可以使用 awk而不是 grepawk不会在不匹配时返回错误,这意味着无论匹配与否,下面的第一个检查任务都不会出错:

- name: Check whether /tmp/my.conf contains "127.0.0.1"
command: awk /^127.0.0.1$/ /tmp/my.conf
register: checkmyconf
changed_when: False


- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: checkmyconf.stdout | match("127.0.0.1")

注意,我的第二个任务使用匹配过滤器,如果 awk 找到匹配,它将返回匹配的字符串。

不管检查任务是否匹配,上述替代方法都会产生以下输出:

TASK: [Check whether /tmp/my.conf contains "127.0.0.1"] ***********************
ok: [localhost]

恕我直言,这是一个更好的方法,因为您不会忽略第一个任务中的其他错误(例如,如果指定的文件不存在)。

另一种方法是使用“替换模块”,然后使用“ lininfile 模块”。

该算法与要更改两个变量的值时使用的算法关闭。

  • 首先,使用“ place module”检测您要查找的行是否在这里,然后用其他内容更改它。(比如同一行 + 结尾的东西)。
  • 如果“替换”是真的,这意味着你的行在这里,然后用特殊性替换新行,用新行查找。
  • 否则你要找的线路不在这里。

例如:

# Vars
- name: Set parameters
set_fact:
newline      : "hello, i love ansible"
lineSearched : "hello"
lineModified : "hello you"


# Tasks
- name: Try to replace the line
replace:
dest    : /dir/file
replace : '\{\{ lineModified }} '
regexp  : '\{\{ lineSearched }}$'
backup  : yes
register  : checkIfLineIsHere


- name: Line is here, change it
lineinfile:
state   : present
dest    : /dir/file
line    : '\{\{ newline }}'
regexp  : '\{\{ lineModified }}$'
when: checkIfLineIsHere.changed
  • 如果文件包含“ hello”,它将变成“ hello you”,然后在结尾处变成“ hello,i love anable”。
  • 如果文件内容不包含“ hello”,则不修改该文件。

有了同样的想法,你可以做一些事情,如果 line Search 在这里:

# Vars
- name: Set parameters
set_fact:
newline      : "hello, i love ansible"
lineSearched : "hello"
lineModified : "hello you"


# Tasks
- name: Try to replace the line
replace:
dest    : /dir/file
replace : '\{\{ lineModified }} '
regexp  : '\{\{ lineSearched }}$'
backup  : yes
register  : checkIfLineIsHere


# If the line is here, I want to add something.
- name: If line is here, do something
lineinfile:
state   : present
dest    : /dir/file
line    : '\{\{ newline }}'
regexp  : ''
insertafter: EOF
when: checkIfLineIsHere.changed


# But I still want this line in the file, Then restore it
- name: Restore the searched line.
lineinfile:
state   : present
dest    : /dir/file
line    : '\{\{ lineSearched }}'
regexp  : '\{\{ lineModified }}$'
when: checkIfLineIsHere.changed
  • 如果文件包含“ hello”,那么行的末尾仍然会包含“ hello”和“ hello,i love anable”。
  • 如果文件内容不包含“ hello”,则不修改该文件。

一起使用 check _ mode、 register 和 false _ when。如果 lineinfile 模块对正在检查的文件进行任何更改,则此操作将使任务失败。Check _ mode 确保即使不这样做,也不会发生任何更改。

- name: "Ensure /tmp/my.conf contains '127.0.0.1'"
lineinfile:
name: /tmp/my.conf
line: "127.0.0.1"
state: present
check_mode: yes
register: conf
failed_when: (conf is changed) or (conf is failed)

User robo 的 regexp & absent方法相当干净,所以我在这里充实了它,以便于使用,并从@assylias 和@Olivier 的评论中添加了改进:

- name: Ensure /tmp/my.conf contains 127.0.0.1
lineinfile:
path: /tmp/my.conf
regexp: '^127\.0\.0\.1.*whatever'
state: absent
check_mode: yes
changed_when: false
register: out


- debug:
msg: "Yes, line exists."
when: out.found


- debug:
msg: "Line does NOT exist."
when: not out.found

您可以在这个场景中使用文件插件。

为了设置一个事实,你可以在其他任务中使用... 这个工作。

- name: Check whether /tmp/my.conf contains "127.0.0.1"
set_fact:
myconf: "\{\{ lookup('file', '/tmp/my.conf') }}"
ignore_errors: yes


- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: "'127.0.0.1' in myconf"

要检查文件内容作为任务的条件... 这应该可以。

- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: "'127.0.0.1' in lookup('file', '/tmp/my.conf')"

另一个解决方案,对于其他目的也很有用,是逐行遍历文件的内容

- name: get the file
slurp:
src: /etc/locale.gen
register: slurped_file


- name: initialize the matches list
set_fact:
MATCHES: []


- name: collect matches in a list
set_fact:
MATCHES: "\{\{ MATCHES + [line2match] }}"
loop: "\{\{ file_lines }}"
loop_control:
loop_var: line2match
vars:
- decode_content: "\{\{ slurped_file.content | b64decode }}"
- file_lines: "\{\{ decode_content.split('\n') }}"
when: '"BE" in line2match'
  

- name: report matches if any
debug:
msg: "Found \{\{ MATCHES | length }} matches\n\{\{ MATCHES }}"
when: 'listlen | int > 0'
vars:
listlen: "\{\{ MATCHES | length }}"

如果您将此机制用于 jinja regex _ place 筛选器,则可以使用它从匹配的行中获取特定的值