bash Ansible - 高级 shell 命令执行格式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25435648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:12:32  来源:igfitidea点击:

Ansible - Advanced shell command execution format

bashshellloopsansibleansible-playbook

提问by Khan

I have 3 variables named IPOctet, ServerIPRange and epcrange. If I perform the following operation in my terminal, it works perfectly

我有 3 个名为 IPOctet、ServerIPRange 和 epcrange 的变量。如果我在我的终端中执行以下操作,它会完美运行

IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc)

How to I do something similar in a ansible inside a task, for e.g

如何在任务中的 ansible 中做类似的事情,例如

---
- hosts: localhost
  gather_facts: False

  vars_prompt:
    - name: epcrange
      prompt: Enter the number of EPCs that you want to configure
      private: False
      default: "1"
    - name: serverrange
      prompt: Enter the number of Clients that you want to configure
      private: False
      default: "1"
    - name: ServerIPRange
      prompt: Enter the ServerIP range
      private: False
      default: '128'
    - name: LastIPOctet
      prompt: Enter The last Octet of the IP you just entered
      private: False
      default: '10'

  pre_tasks:


    - name: Set some facts
      set_fact:
        ServerIP1: "{{ServerIP}}"
        ServerIPRange1: "{{ServerIPRange}}"
        IPOctet: "{{LastIPOctet}}"

    - name: local action math
      local_action: shell {{IPOctet}}=$(echo "${{ServerIPRange}}/${{epcrange}}+${{IPOctet}}" | bc)  # Proper Syntax?
      with_sequence: start=1 end=4
      register: result
      ignore_errors: yes

What is the proper syntax for this command? Maybe using shell echo "......." . I just need to save the contents of this command into the IPOctet variable and IPOctet will change with each loop iteration and the results should be stored in my result register

此命令的正确语法是什么?也许使用 shell echo "......." 。我只需要将此命令的内容保存到 IPOctet 变量中,IPOctet 将随着每次循环迭代而改变,结果应存储在我的结果寄存器中

P.S: how can I access the individual items in the array separately?

PS:如何分别访问数组中的各个项目?

Edit: Is anything like this possible, currently it just does the calculation once and stores it 4 times in the register...

编辑:这样的事情有可能吗,目前它只计算一次并将其存储在寄存器中 4 次...

- name: bashless math
  set_fact:
    IPOctet: "{{ (ServerIPRange|int/epcrange|int)+IPOctet|int }}"
  register: IPOctet
  with_sequence: "start=1 end={{stop}} "
  register: my_ip_octet

采纳答案by Derek Baum

  1. Your terminal expression reassigns the IPOctet shell variable, so it gives a different result each time it is executed. This is fine, but difficult to reproduce in Ansible:

    $ IPOctet=10 ServerIPRange=128 epcrange=1
    $ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
    138
    
    $ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
    266
    
  2. The syntax: "shell {{IPOctet}}=$(echo ..."does NOT assign to the Ansible variable. The shell attempts to execute a command like "10=138", which is not found.

  3. When register is used within a loop, the target variable is not set until the loop completes - so your expression always sees the original value for {{IPOctet}}.

  4. A solution is to run the whole loop as a single shell command:

    - name: local action math2
      local_action: shell IPOctet={{IPOctet}}; for i in 1 2 3 4; do IPOctet=$(expr {{ServerIPRange}} / {{epcrange}} + $IPOctet); echo $IPOctet; done
      register: result
    

    NOTE:I've used the exprcommand rather than bc, but the results are the same.

  5. You can iterate over these results using result.stdout_lines:

    - name: iterate results
      local_action: debug msg={{item}}
      with_items: result.stdout_lines
    
  1. 您的终端表达式重新分配了 IPOctet shell 变量,因此每次执行时都会给出不同的结果。这很好,但很难在 Ansible 中重现:

    $ IPOctet=10 ServerIPRange=128 epcrange=1
    $ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
    138
    
    $ IPOctet=$(echo "$ServerIPRange/$epcrange+$IPOctet" | bc); echo $IPOctet
    266
    
  2. 语法:"shell {{IPOctet}}=$(echo ..."不分配给 Ansible 变量。shell 尝试执行类似 的命令"10=138",但未找到该命令。

  3. 在循环中使用 register 时,在循环完成之前不会设置目标变量 - 因此您的表达式始终会看到{{IPOctet}}.

  4. 一种解决方案是将整个循环作为单个 shell 命令运行:

    - name: local action math2
      local_action: shell IPOctet={{IPOctet}}; for i in 1 2 3 4; do IPOctet=$(expr {{ServerIPRange}} / {{epcrange}} + $IPOctet); echo $IPOctet; done
      register: result
    

    注意:我使用了expr命令而不是bc,但结果是一样的。

  5. 您可以使用 result.stdout_lines 迭代这些结果:

    - name: iterate results
      local_action: debug msg={{item}}
      with_items: result.stdout_lines
    

回答by Ramesh Raithatha

Firstly your Jinja template is incorrect, every single variable needs to be surrounded with a pair of brackets. You can not use multiple variables within single pair of brackets. For example,

首先你的 Jinja 模板不正确,每个变量都需要用一对括号括起来。您不能在一对括号内使用多个变量。例如,

{{ ServerIPRange }}

Secondly, set_fact is used only to set a fact value. You can not run shell commands using set_fact. You should use shell module instead.

其次, set_fact 仅用于设置事实值。您不能使用 set_fact 运行 shell 命令。您应该改用 shell 模块。

- name: local action math
  local_action: shell {{ IPOctet }}=$(echo {{ ServerIPRange|int }}/{{ epcrange|int }}+{{ IPOctet|int }}" | bc)
  with_sequence: start=1 end=4
  register: result
  ignore_errors: yes

Ansible will do the calculation 4 times and store it in a list as 4 different elements. You can check what all is stored inside this list and can even access it by looping over it.

Ansible 将进行 4 次计算并将其作为 4 个不同的元素存储在列表中。您可以检查此列表中存储的所有内容,甚至可以通过循环访问它。

- debug: msg={{ result }}

Hope this helps :)

希望这可以帮助 :)