On my CentOS machine I wrote a script which tells me whether a service is installed or not.
Here is the script
count=$(chkconfig --list | grep -c "$1")
if [ $count = 0 ]; then
echo "False"
else
echo "True"
fi
The problem is that the output of the command always includes the starting lines of the chkconfig output. For example here is the output of script.sh network
[root#vm ~]# ./script.sh network
Note: This output shows SysV services only and does not include native
systemd services. SysV configuration data might be overridden by native
systemd configuration.
If you want to list systemd services use 'systemctl list-unit-files'.
To see services enabled on particular target use
'systemctl list-dependencies [target]'.
True
It seems that the count variable correctly contains the count of grep occurrences but the script will always output the chkconfig header lines, even though I echo only "True" or "False" in the script.
Why does this happen? And how to hide those lines?
This is because chkconfig --list initially returns a header through stderr. Just silence it by using 2>/dev/null:
count=$(chkconfig --list 2>/dev/null | grep -c "$1")
# ^^^^^^^^^^^
Note also that the whole if / else block can be reduced to a mere:
chkconfig --list 2>/dev/null | grep -q "$1" && echo "True" || echo "False"
Since we use the -q option of grep which (from man grep) does exit immediately with zero status if any match is found.
Related
I am specifying my TLS certs in /etc/default/docker, like this:
DOCKER_OPTS="-H=unix:// --tlsverify --tlscacert=/etc/docker/mynewca.pem
--tlscert=/etc/docker/mynewcert.pem
--tlskey=/etc/docker/mynewkey.pem -H=0.0.0.0:2376"
However, every time my Docker host restarts, my settings are overridden with the defaults:
DOCKER_OPTS="-H=unix:// --tlsverify --tlscacert=/etc/docker/ca.pem
--tlscert=/etc/docker/cert.pem
--tlskey=/etc/docker/key.pem -H=0.0.0.0:2376"
This means that I can not communiate with the Docker daemon remotely until I reconfigure DOCKER_OPTS and run
sudo service restart docker
upstart is starting the Docker daemon, and it looks like the script section of /etc/init/docker.conf is overriding DOCKER_OPTS, although I can't find where it's getting the defaults from.
script
# modify these in /etc/default/$UPSTART_JOB (/etc/default/docker)
DOCKERD=/usr/bin/dockerd
DOCKER_OPTS=
if [ -f /etc/default/$UPSTART_JOB ]; then
. /etc/default/$UPSTART_JOB
fi
exec "$DOCKERD" $DOCKER_OPTS --raw-logs
end script
# Don't emit "started" event until docker.sock is ready.
# See https://github.com/docker/docker/issues/6647
post-start script
DOCKER_OPTS=
DOCKER_SOCKET=
if [ -f /etc/default/$UPSTART_JOB ]; then
. /etc/default/$UPSTART_JOB
fi
if ! printf "%s" "$DOCKER_OPTS" | grep -qE -e '-H|--host'; then
DOCKER_SOCKET=/var/run/docker.sock
else
DOCKER_SOCKET=$(printf "%s" "$DOCKER_OPTS" | grep -oP -e '(-H|--host)\W*unix://\K(\S+)' | sed 1q)
fi
if [ -n "$DOCKER_SOCKET" ]; then
while ! [ -e "$DOCKER_SOCKET" ]; do
initctl status $UPSTART_JOB | grep -qE "(stop|respawn)/" && exit 1
echo "Waiting for $DOCKER_SOCKET"
sleep 0.1
done
echo "$DOCKER_SOCKET is up"
fi
end script
Which
You may want to use the docker configuration file that is usually located in /etc/docker/daemon.json. See here for more information on the configuration:
https://docs.docker.com/engine/reference/commandline/dockerd//#daemon-configuration-file
In your case, the "tlscacert" option might be of special interest.
Nevertheless, the location of the configuration file may really depend on the OS and distribution (I remember the famous Gentoo /etc/conf.d/ directory)
I am trying to get the service status (for a /bin/sh script) and start it if is not running.
I found some scripts, but does not work for centos 7.
There are, as usual, multiples ways to do this. Just one example, that check if postfix is running:
#!/bin/sh
PID=`cat /var/spool/postfix/pid/master.pid`
# echo $PID
PS=`/bin/ps axu | grep $PID | grep -v grep`
# echo $PS
if [ "$PS" = "" ]
then
/sbin/service postfix restart
fi
You could use "pid" file, or try to detect if process is running (parsing output of "ps axu |grep process_name"), or parse output of "service process status" command, etc, etc.
What is the best way in bash to check if a service is installed? It should work across both Red Hat (CentOS) and Ubuntu?
Thinking:
service="mysqld"
if [ -f "/etc/init.d/$service" ]; then
# mysqld service exists
fi
Could also use the service command and check the return code.
service mysqld status
if [ $? = 0 ]; then
# mysqld service exists
fi
What is the best solution?
To get the status of one service without "pinging" all other services, you can use the command:
systemctl list-units --full -all | grep -Fq "$SERVICENAME.service"
By the way, this is what is used in bash (auto-)completion (see in file /usr/share/bash-completion/bash_completion, look for _services):
COMPREPLY+=( $( systemctl list-units --full --all 2>/dev/null | \
awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' ) )
Or a more elaborate solution:
service_exists() {
local n=$1
if [[ $(systemctl list-units --all -t service --full --no-legend "$n.service" | sed 's/^\s*//g' | cut -f1 -d' ') == $n.service ]]; then
return 0
else
return 1
fi
}
if service_exists systemd-networkd; then
...
fi
Hope to help.
Rustam Mamat gets the credit for this:
If you list all your services, you can grep the results to see what's in there. E.g.:
# Restart apache2 service, if it exists.
if service --status-all | grep -Fq 'apache2'; then
sudo service apache2 restart
fi
On a SystemD system :
serviceName="Name of your service"
if systemctl --all --type service | grep -q "$serviceName";then
echo "$serviceName exists."
else
echo "$serviceName does NOT exist."
fi
On a Upstart system :
serviceName="Name of your service"
if initctl list | grep -q "$serviceName";then
echo "$serviceName exists."
else
echo "$serviceName does NOT exist."
fi
On a SysV (System V) system :
serviceName="Name of your service"
if service --status-all | grep -q "$serviceName";then
echo "$serviceName exists."
else
echo "$serviceName does NOT exist."
fi
In systemd (especially in Debian), it doesn't seems to work properly using the various answers from here. For some services like pure-ftpd if it's in disabled mode, it will not show up in service list when you trigger this command:
systemctl --all --type service
and when you start again the pure-ftpd with systemctl start pure-ftpd the list will appear again. So listing the service using systemctl --all --type service will not work for all services. Take a look at this for more information.
So, this is the best code so far (improvement from #jehon's answer) to check if a service is exist (even it has status inactive, dead or whatever status it is):
#!/bin/bash
is_service_exists() {
local x=$1
if systemctl status "${x}" 2> /dev/null | grep -Fq "Active:"; then
return 0
else
return 1
fi
}
if is_service_exists 'pure-ftpd'; then
echo "Service found!"
else
echo "Service not found!"
fi
Explanation:
If systemctl status found a service, it must have a text 'Active:' we filter using grep and it would return 0. If there is no 'Active:' text it would return 1.
If systemctl status does not find the 'Active:' text, it will print out a standard error. So, I put redirection 2> /dev/null to redirect the standard error. For example, if you are looking for the non existence service, you would get this error message if you don't put that error redirection:
Unit pure-ftpdd.service could not be found.
We don't want to have the above standard error message if you are doing scripting
EDIT:
Another method is to list out unit files which able to detect disabled service as pointed by #Anthony Rutledge for Debian system:
systemctl list-unit-files --type service | grep -F "pure-ftpd"
But using this method will not always work especially for older system because some unit files might not be detected using this command as explained in here. Also, using this method is slower if you have large unit-files that need to be filtered (as commented by #ygoe about heavy load on a small computer).
To build off of Joel B's answer, here it is as a function (with a bit of flexibility added in. Note the complete lack of parameter checking; this will break if you don't pass in 2 parameters):
#!/bin/sh
serviceCommand() {
if sudo service --status-all | grep -Fq ${1}; then
sudo service ${1} ${2}
fi
}
serviceCommand apache2 status
After reading some systemd man pages ...
https://www.freedesktop.org/software/systemd/man/systemd.unit.html
... and systemd.services(5)....
... and a nice little article ...
https://www.linux.com/learn/understanding-and-using-systemd
I believe this could be an answer.
systemctl list-unit-files --type service
Pipe to awk {'print $1'} to just get a listing of the service units.
Pipe to awk again to get the service names exclusively. Change the field separator to the period with -F.
awk -F. {'print $1'}
In summary:
systemctl list-unit-files --type service | awk {'print $1'} | awk -F. {'print $1'}
With variation and augmentation of the base solution, you can determine the state of your system's services by combining a for loop with systemctl is-active $service.
#!/bin/sh
service=mysql
status=$(/etc/init.d/mysql status)
print "$status"
#echo $status > /var/log/mysql_status_log
var=$(service --status-all | grep -w "$Service")
if [ "output" != "" ]; then
#executes if service exists
else
#executes if service does not exist
fi
$Service is the name of the service you want to know if exists.
var will contain something like
[+] apache2
if the service does exist
if systemctl cat xxx >/dev/null 2>&1; then
echo yes
fi
Try this, as ps command can be used in both Ubuntu&RHEL, this should be work in both platform.
#!/bin/bash
ps cax | grep mysqld > /dev/null
if [ $? -eq 0 ]; then
echo "mysqld service exists"
else
echo "mysqld service not exists"
fi
What is the linux command to find if a process say aa.sh is running or not.
ps command does not seem to work and it does not show the shell script names.
Please advise.
Check this
ps aux | grep "aa.sh"
The simplest and efficient solution is :
pgrep -fl aa.sh
Adding to the answers above -
To use in a script, use the following :-
result=`ps aux | grep -i "myscript.sh" | grep -v "grep" | wc -l`
if [ $result -ge 1 ]
then
echo "script is running"
else
echo "script is not running"
fi
Check this
ps -ef | grep shellscripname.sh
You can also find your running process in
ps -ef
The solutions above are great for interactive use, where you can eyeball the result and weed out false positives that way.
False positives can occur if the executable itself happens to match, or any arguments that are not script names match - the likelihood is greater with scripts that have no filename extensions.
Here's a more robust solution for scripting, using a shell function:
getscript() {
pgrep -lf ".[ /]$1( |\$)"
}
Example use:
# List instance(s) of script "aa.sh" that are running.
getscript "aa.sh" # -> (e.g.): 96112 bash /Users/jdoe/aa.sh
# Use in a test:
if getscript "aa.sh" >/dev/null; then
echo RUNNING
fi
Matching is case-sensitive (on macOS, you could add -i to the pgrep call to make it case-insensitive; on Linux, that is not an option.)
The getscript function also works with full or partial paths that include the filename component; partial paths must not start with / and each component specified must be complete. The "fuller" the path specified, the lower the risk of false positives. Caveat: path matching will only work if the script was invoked with a path - this is generally true for scripts in the $PATH that are invoked directly.
Even this function cannot rule out all false positives, as paths can have embedded spaces, yet neither ps nor pgrep reflect the original quoting applied to the command line. All the function guarantees is that any match is not the first token (which is the interpreter), and that it occurs as a separate word, optionally preceded by a path.
Another approach to minimizing the risk of false positives could be to match the executable name (i.e., interpreter, such as bash) as well - assuming it is known; e.g.
# List instance(s) of a running *bash* script.
getbashscript() {
pgrep -lf "(^|/)bash( | .*/)$1( |\$)"
}
If you're willing to make further assumptions - such as script-interpreter paths never containing embedded spaces - the regexes could be made more restrictive and thus further reduce the risk of false positives.
pgrep -f aa.sh
To do something with the id, you pipe it. Here I kill all its child tasks.
pgrep aa.sh | xargs pgrep -P ${} | xargs kill
If you want to execute a command if the process is running do this
pgrep aa.sh && echo Running
I was quite inspired by the last answer by mklement0 - I have few scripts/small programs I run at every reboot via /etc/crontab. I built on his answer and built a login script, which shows if my programs are still running.
I execute this scripts.sh via .profile -file on every login, to get instant notification on each login.
cat scripts.sh
#!/bin/bash
getscript() {
pgrep -lf ".[ /]$1( |\$)"
}
script1=keepalive.sh
script2=logger_v3.py
# test if script 1 is running
if getscript "$script1" >/dev/null; then
echo "$script1" is RUNNING
else
echo "$script1" is NOT running
fi
# test if script 2 is running:
if getscript "$script2" >/dev/null; then
echo "$script2" is RUNNING
else
echo "$script2" is NOT running
fi
here a quick script to test if a shell script is running
#!/bin/sh
scripToTest="your_script_here.sh"
scriptExist=$(pgrep -f "$scripToTest")
[ -z "$scriptExist" ] && echo "$scripToTest : not running" || echo "$scripToTest : runnning"
Give an option to ps to display all the processes, an example is:
ps -A | grep "myshellscript.sh"
Check http://www.cyberciti.biz/faq/show-all-running-processes-in-linux/ for more info
And as Basile Starynkevitch mentioned in the comment pgrep is another solution.
I have tried to run following csh script which ssh to all computers on our network with the purpose of yum installing software passed as arguments. However, the script fails to continue once I have rsh to another host. Is there a way around this problem?
if ($1 == "")then
echo -n "Please enter a package to install\n"
set package=$<
else set package = $#argv
endif
set numlines = `cat $NM_HOME/sh_local/nc_network2.txt | grep -v "^#" | fgrep "%" | wc -l`
while ($numlines>0)
set line = `cat $NM_HOME/sh_local/nc_network2.txt | grep -v "^#" | fgrep "%" | tail -$numlines | head -1`
set host2 = `echo $line | cut -f 1 -d %`
set where = `echo $line | cut -f 2 -d %`
if ($host2 == $this_machine) then
echo "This is $host2....skipping rsh to this machine"
echo ""
goto yum
endif
echo ""
echo "logging into $host2 $where"
echo ""
sleep 1
rsh $host2
yum:
echo ""
echo "Preparing to install $package on $host2"
sudo yum -y install $package
if ($host2 == $this_machine) then
goto decrement
else
logout
goto decrement
endif
decrement:
# numlines--
end
ssh/rsh-ing to another host does not magically continue the execution of your script on that host. Executing ssh hostname in a script has the exact same effect as executing ssh hostname in your shell — it connects to that machine, runs an interactive shell there, and leaves you in that shell. Your script execution will only continue after you close the ssh/rsh connection yourself.
In order to perform some action on that host, you need to provide an explicit command you want to run on that host, like this:
rsh $host2 sudo yum -y install $package
Note that this is only a naive example for illustration purposes; it likely won't be enough to fix the entire logic of your script, but should point you in the right direction.
YES. My answer is provided below only by reading your "Question" and not what you have put up in the code that you posted.
I have been doing this for many years as below.
create a list of hosts with onehost on each line.
enable SSH key based authentication upfront. This can be done manually but I had done it in the past using perl and expect.
run a for loop as below to perform action onall the servers:
for i in cat hosts_list; do ssh $i dmidecode | grep -m 1 'Serial Number:'; done
Above oneliner will give me the serial numbers of all the servers wic are mentioned in the host_list. This a shot example of pulling serial number. however, you can write a full fledged bash script following the exact same logic.
for more advanced requirement, consider using perl and the ssh modules that are available on CPAN