Using bash and watch to monitor qemu-kvm - bash

I'm trying to monitor some qemu-kvm processes using a bash script and watch to show several details like memory/cpu use, resources, ports,etc. Everything is going great until I try to get the IMG file that qemu-kvm is using.
Initially I thought I could get that information from the running process cmd:
ps -p PID -o cmd | tail -1
qemu-kvm -name TEST -drive file=/img/test.qcow2,if=ide,media=disk,cache=none -daemonize
So after plenty of tests I have wrote this little script just to synthesise the problem:
#!/bin/bash
lsof -p PID | grep '/img/' | awk {'print $9'}
The output of this script looks totally fine when I execute it from the command line:
bash testscript
/img/test.qcow2
The problem comes when I try to run the script along with watch:
watch -n1 "bash test-script" or watch -n1 ./test-script
The output is just empty...
Why don't I get any results? I'd be really glad if somebody can help me understanding this.
EDIT: I have found an alternative solution. I am now getting the information from parsing the procfs with some arrays to find the IMG info:
OIFS=$IFS;
IFS='-';
Array=($(cat /proc/PID/cmdline))
for ((i=0; i<${#Array[#]}; ++i))
do
if [[ "${Array[$i]}" == *drive* ]]; then
image=${Array[$i]}
echo $image
fi
done
IFS=$OIFS;
This works fine combined with watch, but I would still like to know what's the problem with the other method. Is lsof limited somehow??

I tried the same process as you; the only difference in my case was the need for sudo. With that it worked. Same issue?
#!/bin/sh
sudo lsof | grep .B.disk.img
watch -n1 sh test

Related

Does this bash script using grep look correct?

I am having some strange rebooting issues and I think it is due to an error in my shell script.
#!/bin/bash
if ps -a | grep -q gridcoin
then
echo nothing
else
sudo reboot -h now
fi
The script is supposed to work like this:
Run the ps -a command so that all processes are listed. Pipe the results to grep and have grep check to see if any of the processes have the word "gridcoin" in them. If gridcoin is running, do nothing. If gridcoin is not one of the running processes, reboot the system.
I have a cron job that runs this script once every five minutes; however, my system keeps rebooting about every five minutes even when I know for a fact that gridcoin is running.
Please take a look at the code and see if it looks right before I start trying to herd other code cats.
Respectfully,
chadrick
I see at least two problems here. First, ps -a will not show processes that don't have a controlling terminal (so, basically, non-interactive processes); you want ps -ax to show all processes.
Second, depending on the timing, the grep -q gridcoin command may be listed as a running process, and of course it finds itself, meaning that it mistakes itself for the gridcoin process. If you have the pgrep program available, replace both ps and grep with it, since it automatically avoids listing itself. Unfortunately, it doesn't have a -q option like grep, so you have to redirect its output to /dev/null:
if pgrep gridcoin >/dev/null
If pgrep is not available, there are two standardish idioms to prevent grep from finding itself:
if ps -ax | grep -q '[g]ridcoin' # Adding brackets prevents it from matching itself
if ps -ax | grep gridcoin | grep -vq grep # Remove grep processes from consideration
Also, as David C. Rankin pointed out, rebooting the entire system to restart one process is overkill; just restart that one process.

Continuously watch a socket file, run command when it doesn't exist?

It seems that when my screen is locked for some period of time, my S.gpg-agent.ssh disappears, and so in order to continue using my key I have to re-initialise it.
Obviously, this is a relatively frequent occurrence, so I've written a function for my shell to kill gpg-agent, restart it, and reset the appropriate environment variables.
This may be a bit of an 'X-Y problem', X being above this line, but I think Y below is more generally useful to know anyway.
How can I automatically run a command when an extant file no longer exists?
The best I've come up with is:
nohup echo "$file" | entr $command &
at login. But entr runs a command when files change, not just deletion, so it's not clear to me how that will behave with a socket.
According to your comment, cron daemon does not fit.
Watch socket file deletion
Try auditd
# auditctl -w /var/run/<your_socket_file> -p wa
$ tail -f /var/log/audit/audit.log | grep 'nametype=DELETE'
Howto run a script if event occurred
If you want to run a script on socketile deletion, you can use while loop, e.g.:
tail -Fn0 /var/log/audit/audit.log | grep 'name=<your_socket_file>' | grep 'nametype=DELETE' \
while IFS= read -r line; do
# your script here
done
thx to Tom Klino and his answer
You don't mention the OS you're using, but if it's linux, you can use inotifywait from the inotify-tools package:
#!/bin/sh
while inotifywait -qq -e delete_self /path/to/S.gpg-agent.ssh; do
echo "Socket was deleted!"
# Recreate it.
done

Different output when running command in bash script vs terminal

When I run the following code in a bash script I receive an output of 2
#!/bin/bash
HIPPO=$(ps -a | grep hippo | wc -l)
echo "$HIPPO"
However when I run the command ps -a | grep hippo | wc -l straight from a command prompt I get an output of 0
Reading the documentation on ps particularly the -a flag, I'm not understanding why the output is different.
How is called your script? If you named it with hippo, it will count in your ps call.
https://superuser.com/questions/935374/difference-between-and-in-shell-script
When you do the command substitution, the command gets runs once according to the above. So I am assuming, the echo is picking a zombie process that ran that command.

bash: test if a process is running with a certain option

I would to know if it's possible to detect if amarok is playing music or not, in bash.
I have tested
#! /bin/bash
if [ "$(pidof amarok --play)" ]
then
echo amarok is playing music!
else
echo amarok is not playing!
fi
But I have this error:
pidof: invalid options on command line!
pidof thinks that --play is its option, and that is of course an error.
It would be better to check if --play is inside the commandline that was used to start amarok:
grep -- --play /proc/$(pidof amarok)/cmdline
Another option is to grep output of ps aux:
ps aux | grep [a]marok.*--play
In the both cases we suppose that there only one amarok running in the system.
Update 1.
To check if any music is playing at the moment,
you can so:
grep RUNNING /proc/asound/card*/pcm*/sub*/status

Check if Mac process is running using Bash by process name

How do you check if a process on Mac OS X is running using the process's name in a Bash script?
I am trying to write a Bash script that will restart a process if it has stopped but do nothing if it is still running.
Parsing this:
ps aux | grep -v grep | grep -c [-i] $ProcessName
...is probably your best bet.
ps aux lists all the currently running processes including the Bash script itself which is parsed out by grep -v grep with advice from Jacob (in comments) and grep -c [-i] $ProcessName returns the optionally case-insensitive integer number of processes with integer return suggested by Sebastian.
Here's a short script that does what you're after:
#!/bin/bash
PROCESS=myapp
number=$(ps aux | grep -v grep | grep -ci $PROCESS)
if [ $number -gt 0 ]
then
echo Running;
fi
EDIT: I initially included a -i flag to grep to make it case insensitive; I did this because the example program I tried was python, which on Mac OS X runs as Python -- if you know your application's case exactly, the -i is not necessary.
The advantage of this approach is that it scales with you -- in the future, if you need to make sure, say, five instances of your application are running, you're already counting. The only caveat is if another application has your program's name in its command line, it might come up -- regular expressions to grep will resolve that issue, if you're crafty (and run into this).
Research the Darwin man pages for ps, grep, and wc.
A shorter solution:
if pgrep $PROCESS_NAME; then
echo 'Running';
fi
Explanation:
pgrep exits with 0 if there is a process matching $PROCESS_NAME running, otherwise it exist with 1.
if checks the exit code of pgrep, and, as far as exit codes go, 0 is success.
Another way is to use (abuse?) the -d option of the killall command. The -d options won't actually kill the process, but instead print what will be done. It will also exit with status 0 if it finds a matching process, or 1 if it does not. Putting this together:
#!/bin/bash
`/usr/bin/killall -d "$1" &> /dev/null`
let "RUNNING = ! $?" # this simply does a boolean 'not' on the return code
echo $RUNNING
To give credit where its due, I originally pulled this technique from a script in the iTunes installer.
This simple command will do the trick. The brackets around the process name prevent the grep command from showing in the process list. Note there is no space after the comma. There may be some portability issues as ps on some unix systems may require a dash before the options:
ps axo pid,command | grep "[S]kype"
The advantage is that you can use the results in an if statement like this:'
if [[ ! $(ps axo pid,command | grep "[i]Tunes.app") ]]; then
open -a iTunes
fi
Or if you prefer this style:
[[ ! $(ps axo pid,command | grep "[S]kype") ]] && open -a Skype || echo "Skype is up"
Another advantage is that you can get the pid by adding a pipe to awk '{print $1}'.
echo "iTunes pid: $(ps axo pid,command | grep "[i]Tunes.app" | awk '{print $1}')"
You can use either killall or kill, depending on if you are trying to find the task by PID or by name.
By Name:
if ! killall -s -0 $PROCESS_NAME >/dev/null 2>&1; then
# Restart failed app, or do whatever you need to prepare for starting the app.
else
at -f $0 +30seconds # If you don't have this on cron, you can use /usr/bin/at
fi
By PID:
if ! kill -0 $PID 2>/dev/null; then
# Restart app, do the needful.
else
at -f $0 +30seconds
fi
If you look at the OSX Manual you will see a different set of process management commands; since it's not the linux kernel, it makes sense that they would manage processes differently.
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/killall.1.html
A sample output from my terminal (striking out the user and hostname, of course):
user#localhost:~$ kill -0 782 # This was my old, stale SSH Agent.
bash: kill: (782) - No such process
user#localhost:~$ echo $?
1
user#localhost:~$ kill -0 813 # This is my new SSH agent, I only just created.
user#localhost:~$ echo $?
0
The return code from a kill -0 will always result in a safe way to check if the process is running, because -0 sends no signal that will ever be handled by an application. It won't kill the application, and "kill" is only called "kill" because it's usually used to stop an application.
When you look at the interfaces it uses in the source, you'll see that it's actually interacting with the process table directly (and not grepping a potentially loaded output from ps), and just sending a signal to an application. Some signals indicate the application should shutdown or stop, while other signals tell it to restart services, or re-read configuration, or re-open file descriptors to log files that have been recently rotated. There are a plethora of things that "kill" and "killall" can do that doesn't terminate the application, and it's used regularly to simply send a signal to the application.
I lack the reputation to comment on the killall answer above, but there's killall -s for doing it without sending any signals:
killall -s "$PROCESSNAME" &> /dev/null
if [ $? -eq 0 ]; then
echo "$PROCESSNAME is running"
# if you also need the PID:
PID=`killall -s "$PROCESSNAME" | awk '{print $3}'`
echo "it's PID is $PID"
fi
It has for sure!
pgrep, pkill and pfind for OpenBSD and Darwin (Mac OS X)
http://proctools.sourceforge.net
(also available via MacPorts: port info proctools )
pidof by nightproductions.net
I've extended a pidof script found on the net to use regular expressions (usually substrings) and be case insensitive
#!/bin/sh
ps axc |awk "BEGIN{ n=tolower(\"$1\")}\
tolower(\$5) ~n {print \$1}";
just create a script named "pidof" with this content, and put it in you path, i.e. in one of the dirs in
echo $PATH
and make it executable (maybe using sudo)
chmod 755 /usr/local/bin/pidof
and use it like this, of course
kill -9 `pidof pyth`
does Mac have pidof? ...
if pidof $processname >/dev/null ; then echo $processname is running ; fi
Perhaps too late for the OP but this may help others who find this thread.
The following modification of the amrox theme above works well for restarting applications on my OS X:
killall -d TextEdit &> /dev/null && killall TextEdit &> /dev/null; open -a TextEdit
I use the following AppleScript to update and restart daemons:
tell application "System Events" to set pwd to POSIX path of container of (path to me)
do shell script "launchctl unload -w /Library/LaunchDaemons/time-test.plist; cp -f " & quoted form of pwd & "/time-test.plist /Library/LaunchDaemons; launchctl load -w /Library/LaunchDaemons/time-test.plist" with administrator privileges
It assumes the original or updated plist file is in the same directory as the AppleScript.

Resources