Calling a shell script that is stored in another shell script variabl - linux

I searched SO but could not find any relevant post with this specific problem. I would like to know how to call a shell script which is stored in a variable of another shell script.
In the below script I am trying to read service name & corresponding shellscript, check if the service is running, if not, start the service using the shell script associated with that service name. tried multiple options shared in various forums(like 'eval' etc) with no luck. please help to provide your suggestions on this.
checker.sh
#!/bin/sh
while read service
do
servicename=`echo $service | cut -d: -f1`
servicestartcommand=`echo $service | rev | cut -d: -f1 | rev`
if (( $(ps -ef | grep -v grep | grep $servicename | wc -l) > 0 ))
then
echo "$servicename Running"
else
echo "!!$servicename!! Not Running, calling $servicestartcommand"
eval "$servicestartcommand"
fi
done < names.txt
Names.txt
WebSphere:\opt\software\WebSphere\startServer.sh
WebLogic:\opt\software\WebLogic\startWeblogic.sh

Your script can be refactored into this:
#!/bin/bash
while IFS=: read -r servicename servicestartcommand; do
if ps cax | grep -q "$servicename"; then
echo "$servicename Running"
else
echo "!!$servicename!! Not Running, calling $servicestartcommand"
$servicestartcommand
fi
done < names.txt
No need to use wc -l after grep's output as you can use grep -q
No need to use read full line and then use cut, rev etc later. You can use IFS=: and read the line into 2 separate variables
No need to use eval in the end

It is much simpler than you expect. Instead of:
eval "$servicestartcommand"
eval should only be used in extreme circumstances. All you need is
$servicestartcommand
Note: no quotes.
As an example, try this on the command-line:
cmd='ls -l'
$cmd
That should work. But:
"$cmd"
will fail. It will look for a program with a space in its name called 'ls -l'.

May be I don't get the idea, but why not use system variables?
export FOO=bar
echo $FOO
bar

Related

Display the name of all running processes in Linux in a file using a bash script

I need to display the name of all running processes in Linux in a file using a bash script. I wrote the code, but didnt succeed:
#!/bin/bash
for i in `ps aux| awk '{print $5}'`;
echo $i > /tmp/test;
done
Need your assistance, Thanks.
Using the for, the syntax is slightly different:
#!/bin/sh
cat /dev/null > /tmp/test
for i in $(ps aux | awk '{print $5}'); do
echo $i >> /tmp/test;
done
You missed the do operator
The output redirector > on a loop should change to appending >>, otherwise only the last value of the loop will be saved.
But as #stark said, the for is not required:
#!/bin/sh
ps aux | awk '{print $5}' > /tmp/test;
I'm not sure, what your output should look like. With your template, and the fixes from Glauco Leme, I only got the VSZ of all the processes.
I assume you need the cmd of each process, then you just can use ps -e --no-headers --format cmd.
In case you need it in a file:
ps -e --no-headers --format cmd > /tmp/test
I hope this will do what you need.

Using grep in an if statement

My goal is to write a shell script take the users that I have already filtered out of a file and check whether those users have a certain string, and if they do, label them as major, if not, nonmajor. My trouble is coming from my first if statement, and I'm not sure if grep is the right way to go in an if statement. Here is what I have:
(
while read i
do
username=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f2`
fullname=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f3`
id=`echo $i | grep -v 'CMPSC 1513' | grep -P -v '(?!.*CPSMA 2923)CPSMA' | cut -d'|' -f4`
if [ $username ]
then
if grep -q "|0510"
then
echo $username":(password):(UID):(GID):"$fullname"+"$id":/home/STUDENTS/majors:/bin/bash"
else
echo $username":(password):(UID):(GID):"$fullname"+"$id":/home/STUDENTS/nonmajors:/bin/bash"
fi
fi
done
)<./cs_roster.txt
Just some info, this is contained in a while loop. In the while loop, i determine whether the person listed should even be major or nonmajor, and my if [ $username ] has been tested and does return all the correct users. At this point the while loop is only running once and then stopping.
Just remove the square brackets and pass $i to grep:
if echo $i | grep -q "|0510"
In your code sample, grep does not have anything to work on.
The "binary operator expected" occurs because you are invoking the command [ with the arguments "grep" and "-q" (you are not invoking grep at all), and [ expects a binary operator where you have specified -q. [ is a command, treated no differently that grep or ls or cat. It is better (IMO) to spell it test, and when invoked by the name test it does not require that its last argument be ]. If you want to use grep in an if statement, just do something like:
if echo "$username" | grep -q "|0510"; then ...
(Although I suspect, depending on the context, there are better ways to accomplish your goal.)
The basic syntax of an if statement is if pipeline; then.... In the common case, the pipeline is the simple command test, and at some point in pre-history, the decision was made to provide the name [ for the test command with the added caveat that its final argument must be ]. I believe this was done in an effort to make if statements look more natural, as if the [ is an operator in the language. Just ignore [ and always use test and much confusion will be avoided.
You can use this code as an exercise. Write an awk script for it, or start with something like
while IFS='|' read -r f1 username fullname id otherfields; do
# I don't know which field you want to test. I will rest with id
if [[ $id =~ ^0510 ]]; then
subdir=majors
else
subdir=nonmajors
fi
echo "${username}:(password):(UID):(GID):${fullname}+${id}:/home/STUDENTS/${subdir}:/bin/bash"
done < <( grep -v 'CMPSC 1513' ./cs_roster.txt | grep -P -v '(?!.*CPSMA 2923)CPSMA' )
This is nice for learning some bash syntax, but consider an awk script for avoiding a while-loop.

Bash Script output is always 'ps' when piping to grep from ps regardless of PID results

given an array of pids and the code:
for i in ${listedPids[#]}
do
runningCheck="ps -u $USER | grep $i"
grepRes=(${runningCheck})
if [[ -n $grepRes ]]
then
echo $grepRes
echo $runningCheck
... code not related to the issue
fi
done
Regardless if those pids are active or not; I keep getting 'ps' from echo $grepRes while the output of echo $runningCheck shows up with the correct user name and pid. What am I missing?
Replace
"ps -u $USER | grep $i"
by
$(ps -u $USER | grep $i)
Command Substitution: Bash performs the expansion by executing your command and replacing the command substitution with the standard output of the
command, with any trailing newlines deleted.
I simplified your script and here's what it should look like.
for i in "${listedPids[#]}"
do
grepRes=$(ps --no-heading -p $i)
if [[ -n "$grepRes" ]]
then
echo "$grepRes"
... code not related to the issue
fi
done
An even shorter code could be written using while loop.
ps --noheading -p "${listedPids[#]}" | while read grepRes
do
echo "$grepRes"
... code not related to the issue
done
As alvits and l0b0 pointed out, I made a few syntax errors: grepRes=(${runningCheck}) when I just wanted to execute that line and not turn it to a list, and the fact pipes and redirects don't work in variables. In the end pgrep did the job as I just needed to continue looping till all the background processes ended.
Maybe you could try eval.
runningCheck1="ps -u $USER"
runningCheck2=" | grep $i"
echo $runningCheck1$runningCheck
eval $runningCheck1$runningCheck2

struck in the logic

I need to write a shell script to see if the ADM Process is down we need to get an alert via email,I have done that below the script,it is working fine if we have installed one ADM server on one machine,But my requirement is i have installed 3 ADM servers on one machine not sure how i can write the shell script to achieve this requirement.
script:-
export ADM =`ps -ef | grep Adm | grep -v grep | wc -l`
if [ $ADM == 0 ];
then
echo "AdmServer is down on Dev $hostname" | mail -s xxxx.gmail.com
fi
Please help me out,
Thanks,
Instead of checking whether $ADM is 0, check whether it's not 3.
ADM=`ps -ef | grep -c '[A]dm`
if [ $ADM -ne 3 ]
then
echo "AdmServer is down on Dev $hostname" | mail -s xxxx.gmail.com
fi
The -c option to grep returns the count of matches, so you don't need to use wc -l. And putting one of the characters in brackets is a trick for parsing ps output so you don't need grep -v grep (because now the argument to grep is no longer the same as the process name you're searching for). And you should use -eq and -ne for comparing numbers; == and != are for comparing strings.
There's no need to use export when assigning a variable that will just be used in that shell script. export is for creating environment variables, which are inherited by child processes.

bash execute command in variable

I have a command in a variable in Bash:
check_ifrunning=\`ps aux | grep "programmname" | grep -v "grep" | wc -l\`
The command checks if a specific program is running at the moment.
Later in my script, I want to query the value of the variable on a point.
If the specific program is running, the script should sleep for 15 minutes.
I solved it like this:
while [ $check_ifrunning -eq 1 ]; do
sleep 300
done
Will the script execute the command in the variable for each single loop-run or will the value in the variable stay after the first execution?
I have more variables in my script which can change their value. This was just one simple example of this.
Notice that check_ifrunning is set only once, in
check_ifrunning=`ps aux | grep "programmname" | grep -v "grep" | wc -l`
and that it is set before the loop:
while [ $check_ifrunning -eq 1 ]; do
sleep 300
done
You could add, for debugging purposes, an echo check_ifrunning is $check_ifrunning statement inside your while loop just before the sleep ...
You probably simply want (using pidof(8)) - without defining or using any check_ifrunning Bash variable:
while [ -n "$(pidof programname)" ]; do
sleep 300
done
Because you want to test if programname is running at every start of the loop!
You should use the more nestable and more readable $(...) instead of backquotes.
Consider reading the Advanced Bash Scripting Guide...
If you are writing a Bash script, consider to start it with
#!/bin/bash -vx
while debugging. When you are satisfied, remove the -vx...
If you want to encapsulate your commands, the proper way to do that is a function.
running () {
ps aux | grep "$1" | grep -q -v grep
}
With grep -q you get the result as the exit code, not as output; you use it simply like
if running "$programname"; then
:
Ideally, the second grep is unnecessary, but I did not want to complicate the code too much. It still won't work correctly if you are looking for grep. The proper solution is pidof.
See also http://mywiki.wooledge.org/BashFAQ/050

Resources