diff --git a/changelogs/fragments/command-stdin-no-newline.yaml b/changelogs/fragments/command-stdin-no-newline.yaml new file mode 100644 index 00000000000..c4cf46d015b --- /dev/null +++ b/changelogs/fragments/command-stdin-no-newline.yaml @@ -0,0 +1,5 @@ +--- +minor_changes: +- command/shell - new `stdin_add_newline` arg allows suppression of + automatically-added newline `\n` character to the specified in the `stdin` + arg. diff --git a/lib/ansible/modules/commands/command.py b/lib/ansible/modules/commands/command.py index 264609dec79..9a3ff5e1280 100644 --- a/lib/ansible/modules/commands/command.py +++ b/lib/ansible/modules/commands/command.py @@ -58,6 +58,12 @@ options: description: - Set the stdin of the command directly to the specified value. version_added: "2.4" + stdin_add_newline: + type: bool + default: yes + description: + - If set to C(yes), append a newline to stdin data. + version_added: "2.8" notes: - If you want to run a command through the shell (say you are using C(<), C(>), C(|), etc), you actually want the M(shell) module instead. Parsing shell metacharacters can lead to unexpected commands being executed if quoting is not done correctly so it is more secure to @@ -189,6 +195,7 @@ def main(): # The default for this really comes from the action plugin warn=dict(type='bool', default=True), stdin=dict(required=False), + stdin_add_newline=dict(type='bool', default=True), ), supports_check_mode=True, ) @@ -201,6 +208,7 @@ def main(): removes = module.params['removes'] warn = module.params['warn'] stdin = module.params['stdin'] + stdin_add_newline = module.params['stdin_add_newline'] if not shell and executable: module.warn("As of Ansible 2.4, the parameter 'executable' is no longer supported with the 'command' module. Not using '%s'." % executable) @@ -255,7 +263,7 @@ def main(): startd = datetime.datetime.now() if not module.check_mode: - rc, out, err = module.run_command(args, executable=executable, use_unsafe_shell=shell, encoding=None, data=stdin) + rc, out, err = module.run_command(args, executable=executable, use_unsafe_shell=shell, encoding=None, data=stdin, binary_data=(not stdin_add_newline)) elif creates or removes: rc = 0 out = err = b'Command would have run if not in check mode' diff --git a/lib/ansible/modules/commands/shell.py b/lib/ansible/modules/commands/shell.py index 471bc496552..f94eb0ba77d 100644 --- a/lib/ansible/modules/commands/shell.py +++ b/lib/ansible/modules/commands/shell.py @@ -60,6 +60,12 @@ options: description: - Set the stdin of the command directly to the specified value. version_added: "2.4" + stdin_add_newline: + type: bool + default: yes + description: + - If set to C(yes), append a newline to stdin data. + version_added: "2.8" notes: - If you want to execute a command securely and predictably, it may be better to use the M(command) module instead. Best practices when writing diff --git a/test/integration/targets/command_shell/tasks/main.yml b/test/integration/targets/command_shell/tasks/main.yml index 5ca92281ded..390afc79d51 100644 --- a/test/integration/targets/command_shell/tasks/main.yml +++ b/test/integration/targets/command_shell/tasks/main.yml @@ -338,5 +338,51 @@ - shell_result7.cmd == 'cat < {{output_dir_test | expanduser}}/afile.txt + args: + stdin: test + stdin_add_newline: no + +- name: make sure content matches expected + copy: + dest: "{{output_dir_test | expanduser}}/afile.txt" + content: test + register: shell_result7 + failed_when: + - shell_result7 is failed or + shell_result7 is changed + +- name: execute a shell command with trailing newline to stdin + shell: cat > {{output_dir_test | expanduser}}/afile.txt + args: + stdin: test + stdin_add_newline: yes + +- name: make sure content matches expected + copy: + dest: "{{output_dir_test | expanduser}}/afile.txt" + content: | + test + register: shell_result8 + failed_when: + - shell_result8 is failed or + shell_result8 is changed + +- name: execute a shell command with trailing newline to stdin, default + shell: cat > {{output_dir_test | expanduser}}/afile.txt + args: + stdin: test + +- name: make sure content matches expected + copy: + dest: "{{output_dir_test | expanduser}}/afile.txt" + content: | + test + register: shell_result9 + failed_when: + - shell_result9 is failed or + shell_result9 is changed + - name: remove the previously created file file: path={{output_dir_test}}/afile.txt state=absent