I wrote an ansible module is bash. It is working fine, but if want to pass arguments to that module and read them in the bash module how can I do that .. please help
- name: get top processes consuming high cpu
gettopprocesses:
numberofprocesses: 5
In library I have bash script
library/gettopprocesses.sh
#!/bin/bash
TPCPU=$(ps aux --sort -%cpu | head -${numberofprocesses}
echo "{\"changed\": false, "\msg\": {"$TPCPU"}}"
exit 0
I write your bask like this: you have to add source $1 to specify you have args
#!/bin/bash
source $1
NUMBERPROC=$numberofprocesses
TPCPU=$(ps aux --sort -%cpu | head -${NUMBERPROC})
printf '{"changed": %s, "msg": "%s", "contents": %s}' "false" "$TPCPU" "contents"
exit 0
You could add a test to check if right arg is given:
#!/bin/bash
source $1
if [ -z "$numberofprocesses" ]; then
printf '{"failed": true, "msg": "missing required arguments: numberofprocesses"}'
exit 1
fi
NUMBERPROC=$numberofprocesses
TPCPU=$(ps aux --sort -%cpu | head -${NUMBERPROC})
printf '{"changed": %s, "msg": "%s", "contents": %s}' "false" "$TPCPU" "contents"
exit 0
Related
This question already has answers here:
How to pipe input to a Bash while loop and preserve variables after loop ends
(3 answers)
Closed 2 years ago.
MY Code
vuln=0 # initialize FLAG variable
test -f /etc/shadow # Check exist /etc/shadow
if [ $? == 1 ]
then
vuln=1 # Not exist /etc/shadow File -> FLAG ON
else
cat /etc/passwd | while read pass_protection # Read 1 Line
do
temp=`echo $pass_protection | cut -d':' -f2` # Parse the line
if [ $temp != "x" ] # If password not encrypted
then
vuln=1 # FLAG ON
break
fi
done
fi
if [ $vuln == 1 ] # Print Result
then
echo "[4-1] Vuln"
else
echo "[4-1] Not Vuln"
fi
/etc/passwd Sample
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
test:test_PASSWORD:10:10:test:/:/
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
This code is Check the /etc/passwd whether password is encrypted or not
In /etc/passwd sample file, test account is not encrypted Password
But, my code cannot catch it
I found out the Initialize FLAG is affect to result
Please can i get some advise?
Thanks
Run sh -x script.sh
+ read pass_protection
+ cut -d: -f2
+ echo uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
+ temp=x
+ [ x != x ]
+ read pass_protection
+ cut -d: -f2
+ echo test:test_PASSWORD:10:10:test:/:/
+ temp=test_PASSWORD
+ [ test_PASSWORD != x ]
+ vuln=1
+ break
+ [ 0 == 1 ]
test.sh: 328: [: 0: unexpected operator
+ echo [4-1] Not Vuln
[4-1] Not Vuln
The problem is cat /etc/passwd | while read. Here, the right hand side of the pipe runs in a subshell. Subshells cannot affect the parent shell. Every variable set in inside while ... done is lost.
To read the file without a subshell use while ... done < /etc/passwd.
Other than that, you could condense the whole script into a single grep command:
if grep -Evq '^[^:]*:x:' /etc/passwd; then
echo vulnerable
else
echo ok
fi
I am currently writing the following script that logs into a remote server and runs couple of commands to verify the performance of the server and prints a message based on the output of those commands .But the ssh doesn't work and returns the stats of the server that hosts the script instead .
Script
#!/bin/bash
#######################
#Function to add hosts to the array
#the following function takes the ip addresses provided while the script is run and stores them in an array
#######################
Host_storing_func () {
HOST_array=()
for i in $# ;do
HOST_array+=(${i});
done
#echo ${HOST_array[*]}
}
#######################
#Calling above function
#######################
Host_storing_func "$#"
############################################################
#Collect Stats of Ping,memory,iowait time test function
############################################################
b=`expr ${#HOST_array[*]} - 1 `
for i in `seq 0 $b` ;do
sshpass -f /root/scripts/passwordFile.txt /usr/bin/ssh student35#${HOST_array[${i}]} << HERE
echo `hostname`
iowaittm=`sar 2 2|awk '/^Average/{print $5};'`
if [ $iowaittm > 10 ];then
echo "IO ==> BAD"
else
echo "IO ==> GOOD"
fi
memoryy=`free -m |grep Swap|awk '{if($2 == 0) print 0;else print (($4 / $2 ) * 100)}'`
if [ ${memoryy} < '10' ] ;then
echo "memory ==> good"
elif [[ "${memory}" -ge 0 ]] && [[ "${memory}" -le 10 ]];then
echo "No Swap"
else
echo "memory ==> bad"`enter code here`
fi
ping -w2 -c2 `hostname` | grep "packet loss"|awk -F, '{print $3}'|awk -F% '{print $1}'|sed 's/^ *//'|awk '{if ($1 == 0) print "Yes" ;else print "No"}'
HERE
done
Output : oc5610517603.XXX.com is the name of the source server
[root#oc5610517603 scripts]# ./big_exercise.sh 9.XXX.XXX.XXX 9.XXX.XXX.XXX
Pseudo-terminal will not be allocated because stdin is not a terminal.
oc5610517603.XXX.com
IO ==> GOOD
No Swap
ping: oc5610517603.ibm.com: Name or service not known
Pseudo-terminal will not be allocated because stdin is not a terminal.
oc5610517603.XXX.com
IO ==> GOOD
No Swap
ping: oc5610517603.XXX.com: Name or service not known
thanks for checking the script , I figured out a way to solve the problem
It is the sshpass command that is causing issue , you just have to put the opening HERE in single quotes if you want to use variables with in the HEREdoc but if the variables are calculated before ssh then you don't have to put opening HERE in single quotes
sshpass -f /root/scripts/passwordFile.txt /usr/bin/ssh -T student35#${i} << 'HERE'
after I changed the sshpass command as above my script worked
I have modified your script a bit.
As suggested by #chepner, I am not using the Host_storing_func.
Heredocs for sshpaas are somewhat tricky. You have to escape every back-tick and $ sign in the heredoc.
Notice the - before the heredoc start, it allows you to indent the heredoc body. Also, try to avoid back-ticks when you can. use $(command) instead.
Hope it helps.
#!/bin/bash
#######################
#Function to add hosts to the array
#the following function takes the ip addresses provided while the script is run and stores them in an array
#######################
array=( "$#" )
user="student35"
############################################################
#Collect Stats of Ping,memory,iowait time test function
############################################################
for host in ${array[#]}; do
sshpass -f /root/scripts/passwordFile.txt /usr/bin/ssh -l ${user} ${host} <<-HERE
thishost=\$(hostname)
echo "Current Host -> \$thishost";
iowaittm=\`sar 2 2|awk '/^Average/{print \$5}'\`
if [ \$iowaittm > 10 ]; then
echo "IO ==> BAD"
else
echo "IO ==> GOOD"
fi
memory=\$(free -m | grep Swap | awk '{if(\$2 == 0) print 0;else print ((\$4 / \$2 ) * 100)}')
if [ \${memory} < '10' ] ;then
echo "memory ==> good"
elif [[ "\${memory}" -ge 0 ]] && [[ "\${memory}" -le 10 ]]; then
echo "No Swap"
else
echo "memory ==> bad"\`enter code here\`
fi
ping -w2 -c2 \`hostname\` | grep "packet loss"|awk -F, '{print \$3}'|awk -F% '{print \$1}'|sed 's/^ *//'|awk '{if (\$1 == 0) print "Yes" ;else print "No"}'
HERE
done
I have written a script to check process is running or not,it work fine but while testing it, i have found that it not include top command count running in other terminal
check-process.sh
#!/bin/sh
OK=1
CRITICAL=0
PROCESS_NUM=$( ps -ef | grep $1 | grep -v "grep "|grep -v "sh"|wc -l )
#echo $PROCESS_NUM
if [ $PROCESS_NUM = $OK ]
then
echo "OK"
elif [ $PROCESS_NUM = $CRITICAL ]
then
echo "CRITICAL"
elif [ $PROCESS_NUM > $OK ]
then
echo "MULTIPLE process are runing"
else
echo "error"
fi
And i run top command in two terminals and run this script as follow:
./check-process.sh top
and out put is 0 CRITICAL , but when i run normal command ps -ef |grep -v "grep "| wc -l it gives two counts.
That mess of greps just has to go.
One "trick" for finding processes by name without finding your grep is to use a regular expression. That is, after all, what the Global Regular Expression Print command is for. You can use parameter expansion to construct a safe regular expression based on your input string, perhaps like this:
#!/bin/sh
if [ -z "$1" ]; then
echo "I'd love me an option." >&2
exit 1
fi
OK=1
CRITICAL=0
x="${1#?}" # make a temporary string missing the 1st chararcter,
re="[${1%$x}]$x" # then place the 1st character within square brackets.
PROC_COUNT=$( ps -ef | grep -w -c "$re" ) # yay, just one pipe.
if [ "$PROC_COUNT" -eq "$OK" ]; then
echo "OK"
elif [ "$PROC_COUNT" -eq "$CRITICAL" ]; then
echo "CRITICAL"
elif [ "$PROC_COUNT" -gt "$OK" ]; then
echo "MULTIPLE process are running"
else
echo "error"
fi
There are a few notable changes here:
I added something to fail with better explanation if no option is given.
The pipeline, of course. And the lines that create $re.
We're using -gt and -eq to test numeric values. man test for details.
I renamed your count variable to be clearer. What is a "PROCESS_NUM" really? Sounds like a PID to me.
All variables are quoted. I don't need to tell you why, you have the Google.
That said, you should also consider using pgrep instead of any sort of counting pipe, if it's available on your system. Try running pgrep and see what your OS tells you.
I would like to be able to create a bash function that can read the exit code of the command before the pipe. I'm not sure it is possible to have access to that.
echo "1" | grep 2 returns a 1 status code
echo "1" | grep 1 returns a 0 status code
Now I would like to add a third command to read the status, with a pipe:
echo "1" | grep 2 | echo $? will echo "0", even if the status code is 1.
I know I can use the echo "1" | grep 2 && echo "0" || echo "1", but I would prefer to write it using a pipe.
Is they anyway to do that (it would be even better if it was working on most shells, like bash, sh, and zsh)
You're going to have to get the exit status before the next stage of the pipeline. Something like
exec 3> debug.txt
{ echo "1"; echo "$?" >&3; } | long | command | here
You can't (easily) encapsulate this in a function, since it would require passing a properly quoted string and executing it via eval:
debug () {
eval "$#"
echo $? >&3
}
# It looks easy in this example, but it won't take long to find
# an example that breaks it.
debug echo 1 | long | command | here
You have to write the exit status to a different file descriptor, otherwise it will interfere with the output sent to the next command in the pipeline.
In bash you can do this with the PIPESTATUS variable
echo "1" | grep 1
echo ${PIPESTATUS[0]} # returns 0
echo "1" | grep 2
echo ${PIPESTATUS[0]} # returns 0
echo "1" | grep 2
echo ${PIPESTATUS[1]} # returns 1
I'm trying to do a bash script which gives me only the first line of man for "n" commands.
example:
$ sh ./start.sh ls wazup top
ls - list directory contents
wazup - manpage does not exist
top - display Linux tasks
This is my current code:
! bin/bash/
while [ -n "$1" ]
do
which $1> /dev/null
man $1 | head -6 | tail -1
if [ $? = 0 ]
then
echo "manpage does not exist"
fi
shift
done
My Output is:
ls - list directory contents
manpage does not exist
No manual entry for wazzup
manpage does not exist
top - display Linux processes
manpage does not exist
Check the status code returned by man, not once it's piped through head and tail (which will be wrong as it will be the return status of tail).
Many Thanks Alex!
Solved it by not using pipes with your help! :)
Here's my final code for anyone that needs it:
#!/bin/bash
while [ -n "$1" ]
do
which $1> /dev/null
if [ $? = 0 ]
then
man -f $1
else
echo "$1: manpage does not exist"
fi
shift
done