I'm trying to save the pgrep -f "instance" output inside a variable in a bash script. For some reason it doesn't work:
here is the code:
function check_running() {
local component_identifier=$1
local process_check=`get_component_param_value $component_identifier $process_check_col | tr -d '\n'`
if [ "$process_check" != "n/a" ]; then
log "process to check: ****""$process_check""****"
pid=`pgrep -f $process_check`
log "pid: " $pid
fi
}
I have tried with different ways, in single and double quotes.
Also, neither this works:
pid=$(pgrep -f "$process_check")
Please note that the process_check variable returns correctly and is definitely working.
I believe the problem is that this field is at the end of the line and may contain a \n char, that is why I've added a tr in the process_check var.
Any idea?
this is the output of the logs:
process to check: ****"instance"****
pid:
I found a way to answer this question:
echo `ps -ef | grep "$process_check" | grep -wv 'grep\|vi\|vim'` | awk '{print $2}'
I hope other people will find this useful
Well, in my case it didn't like the arguments I was trying to pass.
pgrep -f "example" # working
pgrep -f "-f -N example" # not working
Related
So currently i need to grep a "." from a variable and if it is successful than do some work. So currently i am using this code
if echo "$arg3" | grep -iv '\.' ;
then
FS="'$arg4.$arg3'"
fi
Here i will pass the value in $arg3 like test and look for the "." in the variable and if it is not there than add a substring $arg4 and store it to the another variable.
SO my problemis, it is working but when i run my script it will print the $arg3 value as well.
Thanks in regards,
Vivek
You can redirect the grep output to null as below:
if echo "$arg3" | grep -iv '\.' > /dev/null 2>&1
Trying to run a command as a variable but I am getting strange results
Expected result "1" :
grep -i nosuid /etc/fstab | grep -iq nfs
echo $?
1
Unexpected result as a variable command:
cmd="grep -i nosuid /etc/fstab | grep -iq nfs"
$cmd
echo $?
0
It seems it returns 0 as the command was correct not actual outcome. How to do this better ?
You can only execute exactly one command stored in a variable. The pipe is passed as an argument to the first grep.
Example
$ printArgs() { printf %s\\n "$#"; }
# Two commands. The 1st command has parameters "a" and "b".
# The 2nd command prints stdin from the first command.
$ printArgs a b | cat
a
b
$ cmd='printArgs a b | cat'
# Only one command with parameters "a", "b", "|", and "cat".
$ $cmd
a
b
|
cat
How to do this better?
Don't execute the command using variables.
Use a function.
$ cmd() { grep -i nosuid /etc/fstab | grep -iq nfs; }
$ cmd
$ echo $?
1
Solution to the actual problem
I see three options to your actual problem:
Use a DEBUG trap and the BASH_COMMAND variable inside the trap.
Enable bash's history feature for your script and use the hist command.
Use a function which takes a command string and executes it using eval.
Regarding your comment on the last approach: You only need one function. Something like
execAndLog() {
description="$1"
shift
if eval "$*"; then
info="PASSED: $description: $*"
passed+=("${FUNCNAME[1]}")
else
info="FAILED: $description: $*"
failed+=("${FUNCNAME[1]}")
done
}
You can use this function as follows
execAndLog 'Scanned system' 'grep -i nfs /etc/fstab | grep -iq noexec'
The first argument is the description for the log, the remaining arguments are the command to be executed.
using bash -x or set -x will allow you to see what bash executes:
> cmd="grep -i nosuid /etc/fstab | grep -iq nfs"
> set -x
> $cmd
+ grep -i nosuid /etc/fstab '|' grep -iq nfs
as you can see your pipe | is passed as an argument to the first grep command.
into a bash script, I need to grep a contiuous log streaming and when the proper string is filtered, I need to stop the 'tailf' command to move ond with other implementations.
The common command that works is:
tailf /dir/dir/dir/server.log | grep --line-buffered "Started in"
after the "Started in" line is gathered, I need to break down the "tailf" command.
All this stuff into a bash script.
use grep -m1, it means return the first match then stop:
-m num, --max-count=num
Stop reading the file after num matches.
tailf /dir/dir/dir/server.log | grep -m1 "Started in"
Figured out...
tailf /dir/dir/dir/server.log | while read line
do
echo $line | grep "thing_to_grep"
if [ "$?" -eq "0" ]; then
echo "";echo "[ message ]";echo "";
kill -2 -$$
fi
done
$$ is the PID of the current shell, in this case associated to the "tailf" command.
I have a file with many service names, some of them are running, some of them aren't.
foo.service
bar.service
baz.service
I would like to find an efficient way to get the PIDs of the running processes started by the services (for the not running ones a 0, -1 or empty results are valid).
Desired output example:
foo.service:8484
bar.server:
baz.service:9447
(bar.service isn't running).
So far I've managed to do the following: (1)
cat t.txt | xargs -I {} systemctl status {} | grep 'Main PID' \
| awk '{print $3}'
With the following output:
8484
9447
But I can't tell which service every PID belongs to.
(I'm not bound to use xargs, grep or awk.. just looking for the most efficient way).
So far I've managed to do the following: (2)
for f in `cat t.txt`; do
v=`systemctl status $f | grep 'Main PID:'`;
echo "$f:`echo $v | awk '{print \$3}'`";
done;
-- this gives me my desired result. Is it efficient enough?
I ran into similar problem and fount leaner solution:
systemctl show --property MainPID --value $SERVICE
returns just the PID of the service, so your example can be simplified down to
for f in `cat t.txt`; do
echo "$f:`systemctl show --property MainPID --value $f`";
done
You could also do:
while read -r line; do
statuspid="$(sudo service $line status | grep -oP '(?<=(process|pid)\s)[0-9]+')"
appendline=""
[[ -z $statuspid ]] && appendline="${line}:${statuspid}" || appendline="$line"
"$appendline" >> services-pids.txt
done < services.txt
To use within a variable, you could also have an associative array:
declare -A servicearray=()
while read -r line; do
statuspid="$(sudo service $line status | grep -oP '(?<=(process|pid)\s)[0-9]+')"
[[ -z $statuspid ]] && servicearray[$line]="statuspid"
done < services.txt
# Echo output of array to command line
for i in "${!servicearray[#]}"; do # Iterating over the keys of the associative array
# Note key-value syntax
echo "service: $i | pid: ${servicearray[$i]}"
done
Making it more efficient:
To list all processes with their execution commands and PIDs. This may give us more than one PID per command, which might be useful:
ps -eo pid,comm
So:
psidcommand=$(ps -eo pid,comm)
while read -r line; do
# Get all PIDs with the $line prefixed
statuspids=$(echo $psidcommand | grep -oP '[0-9]+(?=\s$line)')
# Note that ${statuspids// /,} replaces space with commas
[[ -z $statuspids ]] && appendline="${line}:${statuspids// /,}" || appendline="$line"
"$appendline" >> services-pids.txt
done < services.txt
OUTPUT:
kworker:5,23,28,33,198,405,513,1247,21171,22004,23749,24055
If you're confident your file has the full name of the process, you can replace the:
grep -oP '[0-9]+(?=\s$line)'
with
grep -oP '[0-9]+(?=\s$line)$' # Note the extra "$" at the end of the regex
to make sure it's an exact match (in the grep without trailing $, line "mys" would match with "mysql"; in the grep with trailing $, it would not, and would only match "mysql").
Building up on Yorik.sar's answer, you first want to get the MainPID of a server like so:
for SERVICE in ...<service names>...
do
MAIN_PID=`systemctl show --property MainPID --value $SERVICE`
if test ${MAIN_PID} != 0
than
ALL_PIDS=`pgrep -g $MAIN_PID`
...
fi
done
So using systemctl gives you the PID of the main process controlled by your daemon. Then the pgrep gives you the daemon and a list of all the PIDs of the processes that daemon started.
Note: if the processes are user processes, you have to use the --user on the systemctl command line for things to work:
MAIN_PID=`systemctl --user show --property MainPID --value $SERVICE`
Now you have the data you are interested in the MAIN_PID and ALL_PIDS variables, so you can print the results like so:
if test -n "${ALL_PID}"
then
echo "${SERVICE}: ${ALL_PIDS}"
fi
I am trying to write a script to find a reverse SSH PID and kill it if present. I am stuck on "awk" as it gives error. below is the script:
a=('ps -aef | grep "ssh -fN" | grep -v grep | awk '{ print $2 }'')
if [ -n "$a" ]
then
echo "String \"$a\" is not null."
kill -9 "$a"
fi
I commented out if, then, kill and fi lines to debug the script. I get following error:
String "ps -aef | grep "ssh -fN" | grep -v grep | awk {" is not null.
I believe parenthesis for awk is creating the problem and I am unable to get a workaround for this. On Command line, this works perfectly and returns the correct PID.
ps -aef | grep "ssh -fN" | grep -v grep | (awk '{ print $2 }'
Once the PID is passed on to variable "a", I need to issue kill command. OS is Centos 6.4
P.S: I am not fluent on scripting but trying to achieve an objective. Help will be highly appreciated!
There are multiple problems with your script.
You need command substitution to store the output of ps pipeline into an array.
You need to check for the number of elements in the array.
Refer to the array instead of the variable.
The following might work for you:
pids=( $(ps -ef | grep '[s]sh -fN' | awk '{print $2}') )
if [ "${#pids[#]}" -gt 0 ]; then
kill -9 "${pids[#]}";
fi
First, if you have grep and then awk, you can get rid of the greps:
ps -aef | grep "ssh -fN" | grep -v grep | awk '{ print $2 }'
ps -aef |awk ' { if ( ($0 ~ /ssh -FN/) && (! $0 ~ /grep/) ) { print $2 } }'
However, instead of using ps, use pgrep.
pgrep -f "ssh -[fN][fN]" # Will match against either 'ssh -fN' or 'ssh -Nf'
There is even a pkill that will do the entire command for you:
pkill -f "ssh -[fN][fN]"
That will find all of the processes that match that particular string and kill them (if they exist).