How does this line of code work in shell? - linux

I got confused about this line of code, could anyone explain how this code work? I can understand that its using a pipeline, but codes in the middle confuses me.
for pid in $(ps -e -f | grep $1 | grep -v $0 | awk '{print $2}')"

Check below details to understand the command, full command will be like this-
cat script.sh
for pid in $(ps -e -f | grep $1 |grep -v $0 | awk '{print $2}')
do
kill -9 $pid
done
You need to execute it like below -
./script.sh vipin
step1 : ps -e -f (will print all the processes running in the server)
step2 : ps -e -f|grep $1 (considering $1 is variable for current user,
in my case is vipin(user) which i will pass with script,so step2
will filter all the process for that user.
step3 : And $0 is the script name (script.sh), which you don't want to kill
that is why you are using grep -v(to exclude)
step4 : awk '{print $2}' to fetch only the process number.

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.

Strange grep behaviour in scripts

In one of my tools is needed the PID of specyfic process in system. I try do this by following command:
parasit#host:~/# ps -ef | grep beam.smp |grep -v grep |awk '{ print $2 }' |head -n1
11982
Works fine, but when i try use the same command in script in the vast majority of cases got PID of grep instead of target process (beam.smp in this case) despite of 'grep -v grep`.
parasit#host:~/# cat getPid.sh
#!/bin/bash
PROC=$1
#GET PID
CMD="ps -ef | grep $PROC |grep -v grep |awk '{ print \$2 }' |head -n1"
P=`eval $CMD`
parasit#host:~/# bash -x ./getPid.sh beam.smp
+ PROC=beam.smp
+ CMD='ps -ef |grep beam.smp |grep -v grep |awk '\''{ print $2 }'\'' |head -n1'
++ eval ps -ef '|grep' beam.smp '|grep' -v grep '|awk' ''\''{' print '$2' '}'\''' '|head' -n1
+++ head -n1
+++ awk '{ print $2 }'
+++ grep -v grep
+++ grep beam.smp
+++ ps -ef
+ P=2189
Interestingly, it is not deterministic, I know it sounds strange, but sometimes it works OK, and sometimes no, I have no idea what it depends on.
How it is possibile? Is there any better method to get rid of "grep" from results?
BR
Parasit
pidof -s is made for that (-s: single ID is returned):
pidof -s "beam.smp"
However, pidof also returns defunct (zombie, dead) processes. So here's a way to get PID of the first alive-and-running process of a specified command:
# function in bash
function _get_first_pid() {
ps -o pid=,comm= -C "$1" | \
sed -n '/'"$1"' *$/{s:^ *\([0-9]*\).*$:\1:;p;q}'
}
# example
_get_first_pid "beam.smp"
-o pid=,comm=: list only PID and COMMAND columns; ie. only list what we need to check; if all are listed then it is more difficult to process later on
-C "$1": of the command specified in -C; ie. only find the process of that specific command, not everything
sed: print only PID for first line that do not have "defunct" or anything after the base command name

Multiple PIDs being stored in PID file

I have a System V init script I've developed that starts a Java program. For some reason whenever the PID file gets created, it contains multiple PIDs instead of one.
Here's the relevant code that starts the service and writes to the PID file:
daemon --pidfile=$pidfile "$JAVA_CMD &" >> $logfile 2>&1
RETVAL=$?
usleep 500000
if [ $RETVAL -eq 0 ]; then
touch "$lock"
PID=$(ps aux | grep -vE 'grep|runuser|bash' | grep <myservice> | awk '{print $2}')
echo $PID > $pidfile
When I test the ps aux... command manually, a single line returns. When running as a script, it appears that this call is returning multiple PIDs.
Example contents in the PID file: 16601 16602 16609 16619 16690. 16619 is the actual process ID found when manually running the ps aux... command mentioned above.
Try reversing your greps. The first one (-vE) may run BEFORE the myservice one starts up. Grep for your service FIRST, then filter out the unwanted lines:
PID=$(ps aux | grep <myservice> | grep -vE 'grep|runuser|bash' | awk '{print $2}')
I encounted the same issue but not the same statement, it was like this:
PID="$(ps -ef|grep command|grep options|grep -v grep|awk '{print $2}')"
in which I used the same grep order as #Marc said in first answer, but did not filter all the unwanted lines.
So I tried the below one and it worked:
PID="$(ps -ef|grep command|grep options|grep -vE 'grep|runuser|bash'|awk '{print $2}')"

Bash script kill command in for loop

I want to kill all processes containing some string. I wrote script for doing this. However, when I execute it, it gets "Killed" signal after first iteration of for loop. This is my code:
#!/bin/bash
executeCommand () {
local pname="$1";
echo $HOSTNAME;
local search_terms=($(ps aux | grep $pname | awk '{print $2}'))
for pros in "${search_terms[#]}"; do
kill -9 "$pros"
echo $pros
done
exit
}
executeCommand "$1" # get the string that process to be killed contains
I execute it like ./my_script.sh zookeeper.
When I delete the line containing kill command, for loop executes until end, otherwise, after first kill command, I get as an output "Killed" and program exits.
What is possible reason for this, and any other solution to reach my goal?
The silly (faulty, buggy) way to do this is to add grep -v grep to your pipeline:
# ${0##*/} expands to the name of the running script
# ...thus, we avoid killing either grep, or the script itself
ps aux | grep -e "$pname" | egrep -v "grep|${0##*/}" | awk '{print $2}'
The better way is to use a tool built for the job:
# pkill already, automatically, avoids killing any of its parent processes
pkill "$pname"
That said, matching processes by name is a bad practice to start with -- you'll also kill less yourproc.log or vim yourproc.conf, not just yourproc. Don't do it; instead, use a proper process supervision system (upstart, DJB daemontools, Apple launchd, systemd, etc) to monitor your long-running daemons and kill or restart them when needed.
By the way -- there's no need for a for loop at all: kill can be passed multiple PIDs on a single invocation, like so:
# a bit longer and bash-specific, but avoids globbing
IFS=$'\n' read -r -d '' -a pids \
< <(ps auxw | awk -v proc="$pname" -v preserve="${0##*/}" \
'$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2 }' \
&& printf '\0')
kill -- "${pids[#]}"
...which could also be formulated as something like:
# setting IFS and running `set -f` necessary to make unquoted expansion safe
( IFS=$'\n'; set -f; exec kill -- \
$(ps auxw | awk -v proc="$pname" -v preserve="${0##*/}" \
'$0 ~ proc && $0 !~ preserve && ! /awk/ { print $2 }') )
grep will show , it's own process . it should be removed using grep -v option
Try like this
for i in ` ps -ef | grep "$pname" | grep -v grep | awk '{print $2}'`
do
kill -9 $i
done

Getting PID of process in Shell Script

I am writing one shell script and I want to get PID of one process with name as "ABCD". What i did was :
process_id=`/bin/ps -fu $USER|grep "ABCD"|awk '{print $2}'`
This gets PID of two processes i.e. of process ABCD and the GREP command itself what if I don't want to get PID of GREP executed and I want PID only of ABCD process?
Please suggest.
Just grep away grep itself!
process_id=`/bin/ps -fu $USER| grep "ABCD" | grep -v "grep" | awk '{print $2}'`
Have you tried to use pidof ABCD ?
It's very straight forward. ABCD should be replaced by your process name.
#!/bin/bash
processId=$(ps -ef | grep 'ABCD' | grep -v 'grep' | awk '{ printf $2 }')
echo $processId
Sometimes you need to replace ABCD by software name. Example - if you run a java program like java -jar TestJar.jar & then you need to replace ABCD by TestJar.jar.
ps has an option for that:
process_id=`/bin/ps -C ABCD -o pid=`
You can also do away with grep and use only awk.
Use awk's expression matching to match the process name but not itself.
/bin/ps -fu $USER | awk '/ABCD/ && !/awk/ {print $2}'
You can use this command to grep the pid of a particular process & echo $b to print pid of any running process:
b=`ps -ef | grep [A]BCD | awk '{ printf $2 }'`
echo $b
ps | pgrep ABCD
You can try the above command to return the process id of the ABCD process.
I found a better way to do this.
top -n 1 | grep "##" | grep -Eo '^[^ ]+'

Resources