I'd like to find all the names of the users that are executing a certain command given as a parameter.
grep must be used.
I have tried: ps aux | grep $1 | cut -d" " -f1, but it's not the desired result.
/usr/ucb/ps aux | awk '/<your_command_as_parameter>/{print $1}'|sort -u
for eg:
> /usr/ucb/ps aux | awk '/rlogin/{print $1}' | sort -u
I guess you're looking for this.
# cat test.sh
ps aux | grep $1 | grep -v grep | awk '{print $1}'
# ./test.sh bash
root
root
root
There is a trick to getting the information for processes but not the process that's searching for the process, which is to make the name into a regex. For example, if you're searching for ls, make the search term into grep '[l]s'. This works unless you're searching for grep itself, or a single-letter command name.
This is the procname script I use; it works with most POSIX shells:
#! /bin/ksh
#
# #(#)$Id: procname.sh,v 1.3 2008/12/16 07:25:10 jleffler Exp $
#
# List processes with given name, avoiding the search program itself.
#
# If you ask it to list 'ps', it will list the ps used as part of this
# script; if you ask it to list 'grep', it will list the grep used as
# part of this process. There isn't a sensible way to avoid this. On
# the other hand, if you ask it to list httpd, it won't list the grep
# for httpd. Beware metacharacters in the first position of the
# process name.
case "$#" in
1)
x=$(expr "$1" : '\(.\).*')
y=$(expr "$1" : '.\(.*\)')
ps -ef | grep "[$x]$y"
;;
*)
echo "Usage: $0 process" 1>&2
exit 1
;;
esac
In bash, you could use the variable substringing operations to avoid the expr commands:
case "$#" in
1) ps -ef | grep "[${1:0:1}]${1:1}"
;;
*)
echo "Usage: $0 process" 1>&2
exit 1
;;
esac
Both of these run ps -ef; you can use ps aux if you prefer. The search for the 'command' name is not constrained to the command portion of the command, so you could use procname root to find processes run by root. The match is also not constrained to a full word; you could consider grep -w for that (a GNU grep extension).
The output of these is the full line of data from ps; if you want just the user (the first field), then pipe the output to awk '{print $1}' | sort -u.
Related
I have the below code to find out the number of instances of current script running that is running with same arg1. But looks like the script creates a subshell and executes this command which also shows up in output. What would be the better approach to find the number of instances of running script ?
$cat test.sh
#!/bin/bash
num_inst=`ps -ef | grep $0 | grep $1 | wc -l`
echo $num_inst
$ps aux | grep test.sh | grep arg1 | grep -v grep | wc -l
0
$./test.sh arg1 arg2
3
$
I am looking for a solution that matches all running instance of ./test.sh arg1 arg2 not the one with ./test.sh arg10 arg20
The reason this creates a subshell is that there's a pipeline inside the command substitution. If you run ps -ef alone in a command substitution, and then separately process the output from that, you can avoid this problem:
#!/bin/bash
all_processes=$(ps -ef)
num_inst=$(echo "$all_processes" | grep "$0" | grep -c "$1")
echo "$num_inst"
I also did a bit of cleanup on the script: double-quote all variable references to avoid weird parsing, used $() instead of backticks, and replaced grep ... | wc -l with grep -c.
You might also replace the echo "$all_processes" | ... with ... <<<"$all_processes" and maybe the two greps with a single grep -c "$0 $1":
...
num_inst=$(grep -c "$0 $1" <<<"$all_processes")
...
Modify your script like this:
#!/bin/bash
ps -ef | grep $0 | wc -l
No need to store the value in a variable, the result is printed to standard out anyway.
Now why do you get 3?
When you run a command within back ticks (fyi you should use syntax num_inst=$( COMMAND ) and not back ticks), it creates a new sub-shell to run COMMAND, then assigns the stdout text to the variable. So if you remove the use of $(), you will get your expected value of 2.
To convince yourself of that, remove the | wc -l, you will see that num_inst has 3 processes, not 2. The third one exists only for the execution of COMMAND.
I'm currently monitoring a log file and my ultimate goal is to write a script that uses tail -n0 -f and execute a certain command once grep finds a correspondence. My current code:
tail -n 0 -f $logfile | grep -q $pattern && echo $warning > $anotherlogfile
This works but only once, since grep -q stops when it finds a match. The script must keep searching and running the command, so I can update a status log and run another script to automatically fix the problem. Can you give me a hint?
Thanks
use a while loop
tail -n 0 -f "$logfile" | while read LINE; do
echo "$LINE" | grep -q "$pattern" && echo "$warning" > "$anotherlogfile"
done
awk will let us continue to process lines and take actions when a pattern is found. Something like:
tail -n0 -f "$logfile" | awk -v pattern="$pattern" '$0 ~ pattern {print "WARN" >> "anotherLogFile"}'
If you need to pass in the warning message and path to anotherLogFile you can use more -v flags to awk. Also, you could have awk take the action you want instead. It can run commands via the system() function where you pass the shell command to run
Okay so here's another one about the StarMade server.
Previously I had this script for detecting a crash, it would simply search through the logs:
#!/bin/bash
cd "$(dirname "$0")"
if ( grep "[SERVER] SERVER SHUTDOWN" log.txt.0); then
sleep 7; kill -9 $(ps -aef | grep -v grep | grep 'StarMade.jar' | awk '{print $2}')
fi
It would find "[SERVER] SERVER SHUTDOWN" and kill the process after that, however this is not a waterproof method, because with different errors it could be possible that the message doesn't appear, rendering this script useless.
So I have this tool that can send commands to the server, but returns an EOF exception when the server is in a crashed state. I basically want to grab the output of this command, and use it in the if-statement above, instead of the current grep command, in such a way that it would execute the commands below when the grep finds "java.io.EOFException".
I could make it write the output to a file and then grep it from there, but I wonder, isn't there a better/more efficient method to do this?
EDIT: okay, so after a bit of searching I put together the following:
if ( java -jar /home/starmade/StarMade/StarNet.jar xxxxx xxxxx /chat) 2>&1 > /dev/null |grep java.io.EOFException);
Would this be a valid if-statement? I need it to match "java.io.EOFException" in the output of the first command, and if it matches, to execute something with "then" (got that part working).
Not sure to solve your problem, but this line:
ps -aef | grep -v grep | grep 'StarMade.jar' | awk '{print $2}'
could be change to
ps -aef | awk '/[S]tarMade.jar/ {print $2}'
The [S] prevents awk from finding itself.
Or just like this to get the pid
pidof StarMade.jar
I am writing a script to kill all instances of the same process. As it is going to be used on Linux, AIX, HP-UX and Solaris, I need to use only built-in bash (sh) functions. That's why killall, pkill, etc. don't work for me.
Once there is only one instance of a process it should be just killed in traditional way:
kill -TERM `ps -ef | grep -v grep | grep $process | awk '{print $2}'`
However sometimes the program has extra instances running and that's why ps -ef | … returns more than one PID. That needs to be reported.
example:
bash-3.2$ ps -ef | grep -v grep | grep perl | awk '{print $2}'
5267
5268
5269
5270
5271
My thought was to store those values in a temporary variable and then send kill signal to each in a for loop.
bash-3.2$ tmp=`ps -ef | grep -v grep | grep perl | awk '{print $2}'`
bash-3.2$ echo $tmp
5267 5268 5269 5270 5271
However I still need the information if such a case occurred (how many instances were present).
It seems I need to check the whole string stored in the tmp variable and maybe count spaces?
Anyway the questions reduces to how to check how many values the $tmp variable stores?
For maximum portability and reliability, use -A (POSIX synonym of -e) and a custom format with -o rather than -f.
Your filtering of the output of ps is brittle: it may match other processes. You've had to exclude the grep process, and you may need to exclude your script as well, and there may be other completely innocent processes caught in the fray (such as your script itself) because their command line happens to contain $process as a substring. Make your filtering as strict as possible. With ps -o pid= -o comm=, you get just two columns (PID and command without arguments) with no header.
You don't need to use a loop to do the killing, kill accepts multiple arguments. For the counting, let the shell do it: you have a whitespace-separated list of numbers, to let the shell do the word splitting (with $(…) outside quotes) and count the number of resulting words ($#).
count_and_kill_processes () {
set -- $(ps -A -o pid= -o comm= |
awk -v "name=$process" '$2 == name {print $1}')
count=$#
if [ $# -ne 0 ]; then kill "$#"; fi
}
count_and_kill_processes foo
# now the number of killed processes is in $count
If your shell is bash or ksh on all machines, you can use an array.
pids=($(ps -A -o pid= -o comm= |
awk -v "name=$process" '$2 == name {print $1}') )
if [[ $# -ne 0 ]]; then kill "$#"; fi
# the number of killed processes is ${#pids}
use xargs:
ps aux | grep -ie perl | awk '{print $2}' | xargs kill -9
You can use a loop which should work in both cases:
for pid in $(ps -ef | grep -v grep | grep $process | awk '{print $2}'); do
echo $pid
done
Or count the number of matches:
if [ $(ps -ef | grep -v grep | grep $process | awk '{print $2}' | wc -l) -gt 1 ]
then
# more than one
fi
I need to implement a shell script that kills a process. The problem is that I need to do a conditional to be able to see if the process is running or not.
This is my code, but it is not working:
#!/bin/sh
if [ -x "MY_PROCCESS_NAME"]; then
killall MY_PROCCESS_NAME
else
echo "Doesn't exist"
fi
This is the error:
line 3: [: missing `]'
to check if a process is running on mac os x you can use:
pid=$(ps -fe | grep 'process name' | grep -v grep | awk '{print $2}')
if you want to reduce the number of shell scripts you can enclose one of the characters of the name of the process in square brackets:
pid=$(ps -fe | grep '[p]rocess name' | awk '{print $2}')
combined in your test this would look like:
pid=$(ps -fe | grep '[p]rocess name' | awk '{print $2}')
if [[ -n $pid ]]; then
kill $pid
else
echo "Does not exist"
fi
it's a little more complicated than you would need to do under linux as you generally have the 'pgrep' command, which is the rough equivalent of the 'ps -fe | grep ... | grep -v grep'
not sure if it would work in OSX, it works in ubuntu.
but as a one liner:
ps aux | awk '$11~/vim/ {PID = $2} END {if (PID) print "kill -9 "PID; else print "echo no process"}' | bash
what it does is it finds a process, in this case, vim and returns the kill -9 pid if no string is found it returns echo no process it then pipes the output to bash.