ansible grep plus awk with shell/command directive - ansible

I am trying run this ansible playbook
- name: Network Getting Started First Playbook Extended
gather_facts: false
hosts: localhost
tasks:
- name: Disable wolverine
shell: 'kubectl -n testns exec dashmpp-head-0 -c container -- bash -c "list versions | grep -w 20220928025228 | awk '{print $9}'"'
register: target_db2_version
failed_when: target_db2_version.stdout == "" or target_db2_version.stderr != ""
This keeps failing with:
shell: 'kubectl -n testns exec dashmpp-head-0 -c container -- bash -c "list versions | grep -w 20220928025228 | awk '{print $9}'"'
^ here
Problem here is with awk '{print $9}' part. If I remove that the command works fine.
Here is what all I have tried already
Tried running the command manually on shell prompt and it works fine
awk \'{print $9}\'
awk '{print \$9}'
awk \'\{print \$9\}\'
Tries using command directive instead of shell

You should use two single quotes to denote a literal single quote within a single-quoted string in YAML:
shell: 'kubectl -n testns exec dashmpp-head-0 -c container -- bash -c "list versions | grep -w 20220928025228 | awk ''{print $9}''"'
or in this case, there is no need to enclose the string in single quotes to begin with:
shell: kubectl -n testns exec dashmpp-head-0 -c container -- bash -c "list versions | grep -w 20220928025228 | awk '{print $9}'"

Related

Getting error when try to list all users on the hosts

I am trying to get all the users I created on the hosts machine. When I run the following command on terminal, I get all the users on the machine.
sudo getent passwd {1000..6000} | cut -d":" -f1
However when I try to run it using ansible, I get an error. I tried all like enquoting in double quotes, escaping the brackets, piping the output to cat etc but nothing is working.
---
- name: "run commands"
become: true
gather_facts: no
hosts: all
tasks:
- name: list all users
shell: getent passwd {1000..6000} | cut -d":" -f1
register: getent
- debug: var=getent.stdout_lines
Note that, per default, Ansible is using /bin/sh, as pointed in the synopsis of the command.
It is almost exactly like the ansible.builtin.command module but runs the command through a shell (/bin/sh) on the remote node.
Source: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html#synopsis
But sh won't interpret a sequence construct like {0..10}.
There are two ways you can overcome this:
Using seq rather:
- shell: getent passwd $(seq 1000 6000) | cut -d":" -f1
register: getent
Specifying to the shell task that you want it executed via bash:
- shell: getent passwd {1000..6000} | cut -d":" -f1
register: getent
args:
executable: /bin/bash

How to extract string of command result and use it in a loop

Running a nx affected:apps command gives me this output:
> NX NOTE Affected criteria defaulted to --base=master --head=HEAD
> NX Affected apps:
- app-backend
- app-frontend
- app-something
- app-anything
I need to get all the application names and use them again for a command call.
So I started with that
output=$(nx affected:apps)
echo "$output" | grep -E "^\W+app-(\w+)"
This gives me
- app-backend
- app-frontend
- app-something
- app-anything
But I need to get the names only instead to run foo --name={appname} four times.
Also not quite sure how to use it in a loop. Quite new to bash scripting :-(
You may use -o (show matches only) with -P (perl regex moode) in gnu-grep:
nx affected:apps |
grep -oP "^\W+app-\K\w+" |
xargs -I {} docker build -t {} .
If gnu-grep isn't available then use this awk command:
nx affected:apps |
awk -F- '/app-/{print $3}' |
xargs -I {} docker build -t {} .
I don't have nx command here but you can try using xargs:
nx affected:apps | grep '^ -' | cut -d' ' -f4 | xargs -I{} echo docker build -t {} ./dist/{}
Remove echo to actually run the command.
You can use the --plain option:
nx affected:apps --plain
the command should return all the affected apps with space as a divider. You can then store those to a bash array and cycle through them in a for loop, running the command you need:
#!/bin/bash
AFFECTED=($(./node_modules/.bin/nx affected:apps --plain))
for t in ${AFFECTED[#]}; do
echo $t
done

ssh remote command execution quoting and piping awk

I'm working on a script, that should find certain disks and add hostname to them.
I'm using this for 40 servers with a for loop in bash
#!/bin/bash
for i in myservers{1..40}
do ssh user#$i findmnt -o SIZE,TARGET -n -l |
grep '1.8T\|1.6T\|1.7T' |
sed 's/^[ \t]*//' |
cut -d ' ' -f 2 |
awk -v HOSTNAME=$HOSTNAME '{print HOSTNAME ":" $0}'; done |
tee sorted.log
can you help out with the quoting here? It looks like awk gets piped (hostname) from localhost, not the remote server.
Everything after the first pipe is running locally, not on the remote server.
Try quoting the entire pipeline to have it run on the remote server:
#!/bin/bash
for i in myservers{1..40}
do ssh user#$i "findmnt -o SIZE,TARGET -n -l |
sed 's/^[ \t]*//' |
cut -d ' ' -f 2 |
awk -v HOSTNAME=\$HOSTNAME '{print HOSTNAME \":\" \$0}'" ;
done | tee sorted.log
This is a shorter version of your stuff:
findmnt -o SIZE,TARGET -n -l |
awk -v HOSTNAME=$HOSTNAME '/M/{print HOSTNAME ":" $2}'
Applied to the above:
for i in myservers{1..40}
do ssh user#$i bash -c '
findmnt -o SIZE,TARGET -n -l |
awk -v HOSTNAME=$HOSTNAME '"'"'/M/{print HOSTNAME ":" $2}'"'"' '
done |
tee sorted.log
see: How to escape the single quote character in an ssh / remote bash command?

Scape quotes on remote command

I'm try to pass a commadn on remote server.
Command work fine on local server, but when try pass on remote server trought ssh get error for bad scpaing
ls -t /root/mysql/*.sql | awk 'NR>2 {system(\"rm \"" $0 \"\"")}'
Full comnand
ssh root#host -p XXX "mysqldump --opt --all-databases > /root/mysql/$(date +%Y%m%d%H%M%S).sql;ls -t /root/mysql/*.sql | awk 'NR>2 {system(\"rm \"" $0 \"\"")}'"
Actually no need to use awk and avoid all that quotes escaping:
ls -t /root/mysql/*.sql | tail -n +1 | xargs rm
This is assuming your *.sql files don't have any whitespaces otherwise you should use stat command and sort the output using sort.

Using awk inside ssh from ruby

When running the command:
puts `ssh -o StrictHostKeyChecking=no -i keyfile user#host "sudo cat file | awk '/^server/ {print \$2}' | sort -u"`
After running this command, its only counts the ^server, but it ignores the print $2 command.
i get the whole line instead of just the 2nd word.
You're running through a couple of shell processing layers, so you need an additional backslash:
puts `ssh -o StrictHostKeyChecking=no -i keyfile user#host "sudo cat file | awk '/^server/ {print \\$2}' | sort -u"`
What happens if you change this:
sudo cat file | awk '/^server/ {print \$2}' | sort -u
to this:
sudo cat file | grep '/^server' | awk '{ print \$2 }' | sort -u
If still not working, try not escaping the $ - try $2 instead of \$2
Might be more maintainable to split it up into pieces. Also using ruby's single quoting mechanism works to send the command as you intend.
cmd = %q(sudo cat file | awk '/^server/ {print $2}' | sort -u)
puts %x(ssh -o StrictHostKeyChecking=no -i keyfile user#host #{cmd})

Resources