I'm just reading the script module documentation, and I don't understand what the cmd property is good for. The documentation states that script:
The script module takes the script name followed by a list of space-delimited arguments.
Where cmd also takes a script followed by a list of arguments.
Can someone explain the difference?
It is just a formatting option. The following two tasks are functionally identical:
- name: Run a script with arguments (using 'cmd' parameter)
script:
cmd: /some/local/script.sh --some-argument 1234
- name: Run a script with arguments (freeform)
script: /some/local/create_file.sh --some-argument 1234
Related
I'm working on a question that wants me to deploy a pod with the nginx image. The pod should sleep for 5000 seconds.
The command can be specified like so:
command: ["sleep", "5000"]
or like so:
command:
- sleep
- "5000"
Why can't the command be specified like so:
command:
- sh
- -c
- sleep "5000"
or like so:
command:
- sleep "5000"
In other words, I'm confused about two things:
What does sh -c do? I understand that -c is there to denote arguments, but isn't the sleep command run using sh?
When can the command and args be listed on the same line, and when do they have to be on separate lines? In this example, why doesn't sleep "5000" work? Why do sleep and "5000" have to be on separate lines? Also, why are quotes around the number 5000 required?
Note that command and args as in K8s object definitions or manifest are in-facet entrypoint and cmd fields as found in container image definitions. These are supposed to behave in a certain specific way. for eg: if you look at at how docker images are defined, you would find entrypoint and cmd as 2 highly used fields.
supplying command and/or args in K8s object definition overrides entrypoint and cmd fields of the associated container.
entrypoint in docker image definitions for example is allowed either as a single string (sleep 5000) or as a broken down array (["sleep", "500"]). either ways, it's eventually broken down into an array of arguments (i.e. sleep 5000 becomes ["sleep", "5000"]).
I suppose K8s tries to simplify this by letting you supply this only as an array.
this article is a good reference to understand how entrypoint and cmd work in combination on container image definitions. The behavior feels a bit unnecessarily complicated and I cannot thank K8s contributors more for they simplified it to some extent at least.
The two ways of running the command:
command: ["sleep", "5000"]
Is exactly the same as:
command:
- sleep
- 5000
In both cases, it is interpreted as a list. It's two ways of expressing a list.
The command cannot be specified as command: sleep "5000" because this would be interpreted as a single argument "sleep 5000" rather than as two separate arguments sleep and 5000.
Think of it as running this command in shell:
`"sleep 5000"`
This would be run as a single command and the 5000 would not be interpreted as an argument. Whereas the expression: command: [sleep, 5000] would be interpreted as:
`"sleep"` 5000
# or simply... (same as)
`sleep` "5000"
Thus being interpreted correctly as an argument of sleep.
For sh -c, sh calls the program sh (shell) as the interpreter and the -c flag means to execute the following command as interpreted by this program. -c is the flag that tells the shell to execute the command that follows it. So in this scenario, it would be redundant to use sh -c, and I'm uncertain if that would even execute correctly.
I have a script wrapper.sh it takes a string as an argument.
wrapper.sh
#!/usr/bin/env bash
node ./index.js $1
Now if I pass argument as hello it runs fine but if I pass hello&pwd then it passes full string as an argument to the nodejs file instead of just passing hello in nodejs and running pwd separately.
Example
./wrapper.sh "hello"
# nodejs gets argument hello : Expected
./wrapper.sh "hello&pwd"
# nodejs gets argument hello&pwd : Not Expected
# Requied only hello in nodejs while pwd running separately
I have tried a lot of solutions online but none seem to work except eval and bash -c which I don't want to use because the script doesn't wait for these commands to finish.
Edit
wrapper.sh is executed by a third party software and the content of the script is dynamically configured by the user so there's nothing much in my hand. Job of my module is to just setup the script properly that it is executed by the third party software.
As an example, I am trying to capture the raw commands that are output by the following script:
https://github.com/adampointer/go-deribit/blob/master/scripts/generate-models.sh
I have tried to following a previous answer:
BASH: echoing the last command run
but the output I am getting is as follows:
last command is gojson -forcefloats -name="${struct}" -tags=json,mapstructure -pkg=${p} >> models/${p}/${name%.*}_request.go
What I would like to do is capture the raw command, in other words have variables such as ${struct}, ${p} and ${p}/${name%.*} replaced by the actual values that were used.
How do I do this?
At the top of the script after the hashbang #!/usr/bin/env bash or #!/bin/bash (if there is any) add set -x
set -x Print commands and their arguments as they are executed
Run the script in debug mode which will trace all the commands in the script: https://stackoverflow.com/a/10107170/988525.
You can do that without editing the script by typing "bash generate-models.sh -x".
is it possible to write the shell command in one line ?
- shell: my command
register: var
run_once: true
this work
- shell: "my command" register=var run_once=true
this does not work
Shell is a one-to-one comparison to running the command yourself. From Ansible documentation:
The shell module takes the command name followed by a list of
space-delimited arguments.
So my_command register=var run_once=true would be correct if my_command runs that way when you run it in your local shell.
While you didn't ask about it, it's worth noting that it looks like you're trying to add parameters to the shell module that don't exist, so the first example you provided would have to use the args parameter:
- name: Execute my command in a remote shell
shell: my_command
args:
register: var
run_once: true
Documented examples of shell are here
i've created simple bash script that do the following
:
#!/usr/bin/env bash
cf ssh "$1"
When I run the command line from the CLI like cf ssh myapp its running as expected, but when I run the script like
. myscript.sh myapp
I got error: App not found
I dont understand what is the difference, I've provided the app name after I invoke the script , what could be missing here ?
update
when I run the script with the following its working, any idea why the "$1" is not working ...
#!/usr/bin/env bash
cf ssh myapp
When you do this:
. myscript.sh myapp
You don't run the script, but you source the file named in the first argument. Sourcing means reading the file, so it's as if the lines in the file were typed on the command line. In your case what happens is this:
myscript.sh is treates as the file to source and the myapp argument is ignored.
This line is treated as a comment and skipped.
#!/usr/bin/env bash
This line:
cf ssh "$1"
is read as it stands. "$1" takes the value of $1 in the calling shell. Possibly - most likely in your case - it's blank.
Now you should know why it works as expected when you source this version of your script:
#!/usr/bin/env bash
cf ssh myapp
There's no $1 to resolve, so everything goes smoothly.
To run the script and be able to pass arguments to it, you need to make the file executable and then execute it (as opposed to sourcing). You can execute the script for example this way:
./script.bash arg1 arg2