Using bash ps and cut together - bash

I need to extract PID, UID and command fields from 'ps' and I have tried it like this:
ps -L u n | cut -f 1,2,13
For some reason, this behaves as there is no cut command whatsoever. It just returns normal ps output. Then, I tried
ps -L u n | tr -s " " | cut -d " " -f 1,2,13 and this returns total nonsense. Then, I tried playing with it and with this:
ps -L u n | tr -s " " | cut -d " " -f 2,3,14
and this somehow returns what I need (almost, and I don't understand why that almost works), except that it cuts out the command field in the middle of it. How can I get what I need?

ps is printing out space separators, but cut without -d uses the tab character. The tr -s squeezes the spaces together to get more of the separation that you want, but remember that there is the initial set of spaces (squeezed to one) hence why you need to add 1 to each field. Also, there are spaces in the commands for each word. This should work:
ps -L u n | tr -s " " | cut -d " " -f 2,3,14-

Is there any particular reason for using cut?
I guess this will do what you want:
ps -eopid,uid,cmd

You can use awk to clean up your command, like so:
ps -L u n | awk '{ print $1,$2,$13 }'

The question is what to do once you have a list. I find cut kludgy, so instead of cut I pass the list to a while read loop.
"While read" recognizes non-blank values on a line, so in this example, "a" is the first value, "b" is the second and "c" is the rest of the line. I am only interested in the first 2 values, process owner and process ID; and I basically abuse the case statement rather than use an "if". (Even though grep filtered, I don't want to kill processes where the owner name might be embedded elsewhere in the line)
ps -ef | grep owner | grep -v grep | while read a b c;
do
case $a in
"owner")
kill -9 $b
;;
esac;
done

Related

BASH script help using TOP, GREP and CUT

Use Top command which repeats 5 times, pipe the results to Grep and Cut command to print the PID for init process on your screen.
Hi all, I have my line of code:
top -n 5 | grep "init" | cut -d" " -f3 > topdata
But I cannot see any output to verify that it's working.
Also, the next script asks me to use a one line command which shows the total memory used in megabytes. I'm supposed to pipe results from Free to Grep to select or filter the lines with the pattern "Total:" then pipe that result to Cut and display the number representing total memory used. So far:
free -m -t | grep "total:" | cut -c25-30
Also not getting any print return on that one. Any help appreciated.
expanding on my comments:
grep is case sensitive. free says "Total", you grep "total". So no match! Either grep for "Total" or use grep -i.
Instead of cut, I prefer awk when I need to get a number out of a line. You do not know what length the number will be, but you know it will be the first number after Total:. So:
free -m -t | grep "Total:" | awk '{print $2}'
For your top command, if you have no init process (which you should, but it would probably not show in top), just grep for something else to see if your code works. I used cinnamon (running Mint). The top command is:
top -n 5 | grep "cinnamon" | awk '{print $1}'
Replace "cinnamon" by "init" for your requirement. Why $1 in the awk? My top puts the PID in the first column. Adjust accordingly.
Overall, using cut is good when you have a string that is delimited by some character. Ex. aaa;bbb;ccc, you would cut on -d';'. But here the numbers might have different lengths so using cut is not (IMHO) the best solution.
The init process has PID 1, to there's no reason to do like this.
To find the PID of a process in general, I'd recommend:
pidof <name>

Passing a variable to sed inside for loop

I have a for loop written in a script like so:
for((i=0;i<${#hours[#]})); do
dates=("$(last | egrep -v "reboot|wtmp|^$" | sort | tr -s " " | sed "$i q;d" | cut -f5-7 -d' ')")
done
If I simply execute the command assigned to dates in the terminal, replacing $i (inside the sed command) by a number (0,1,2...), it returns me exactly what I want, which is, for instance Nov 15 23:15.
However, when inside the for loop, I seem to have a problem with the sed command not incrementing $i. What am I doing wrong?
Your problem is that you never change i. You should probably update it in the third part of your for statement:
for((i=0;i<${#hours[#]};++i)); do
# ^^^ here

how to omit grep output in conditional statement

On a Mac, I want to determine if there are any sleep assertions present, using pmset. If there are, extract only that information and omit unnecessary information.
If grep returns nothing I want to print "Nothing".
if pmset -g | grep pre ; then pmset -g | grep pre | cut -d'(' -f2 | cut -d')' -f1 ; else printf "Nothing\n" ; fi
The problem is that the first grep result is printed, and so is the formatted one. For example this is what I get if a backup is in progress:
sleep 15 (sleep prevented by backupd)
sleep prevented by backupd
I don't want the first line, and want to discard it. I only want the second line to print ("sleep prevented by backupd").
If the grep result is empty I want to indicate that with the text "Nothing". The above script works OK for that.
There are probably many more elegant solutions but I've been searching days for one.
If i understand your question properly, you simply need to discard the output of first grep irrespective of the output it provides. If it's so, then you can use -q option provided by grep.
From the man page for 'grep':
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was
detected. Also see the -s or --no-messages option. (-q is specified by POSIX.)
Something like this:
if ifconfig | grep -q X; then
ifconfig | grep Mi | cut -d'(' -f2
else
printf "Nothing\n"
fi
Obviously in the above example, output of ifconfig will not change every time. Just used as an example. ;)
Redirect the output to /dev/null:
if pmset -g | grep pre >/dev/null 2>&1 ; then
pmset -g | grep pre | cut -d'(' -f2 | cut -d')' -f1
else
printf "Nothing\n"
fi
This is maybe a little more succinct. It gets grep to only output the part of the line that matches the pattern instead of the whole line, by using grep -o:
#!/bin/bash
SLEEP=$(pmset -g | grep -o "sleep prevented.*[^)]")
if [ -z "$SLEEP" ]; then
echo Nothing
else
echo $SLEEP
fi
The pattern is sleep prevented and any characters following until a ) is encountered.

Cut from column to end of line

I'm having a bit of an issue cutting the output up from egrep. I have output like:
From: First Last
From: First Last
From: First Last
I want to cut out the "From: " (essentially leaving the "First Last").
I tried
cut -d ":" -f 7
but the output is just a bunch of blank lines.
I would appreciate any help.
Here's the full code that I am trying to use if it helps:
egrep '^From:' $file | cut -d ":" -f 7
NOTE: I've already tested the egrep portion of the code and it works as expected.
The cut command lines in your question specify colon-separated fields and that you want the output to consist only of field 7; since there is no 7th field in your input, the result you're getting isn't what you intend.
Since the "From:" prefix appears to be identical across all lines, you can simply cut from the 7th character onward:
egrep '^From:' $file | cut -c7-
and get the result you intend.
you were really close.
I think you only need to replace ":" with " " as separator and add "-" after the "7": like this:
cut -d " " -f 2-
I tested and works pretty well.
The -f argument is for what fields. Since there is only one : in the line, there's only two fields. So changing -f 7 to -f 2- will give you want you want. Albeit with a leading space.
You can combine the egrep and cut parts into one command with sed:
sed -n 's/^From: //gp' $file
sed -n turns off printing by default, and then I am using p in the sed command explicitly to print the lines I want.
You can use sed:
sed 's/^From: *//'
OR awk:
awk -F ': *' '$1=="From"{print $2}'
OR grep -oP
grep -oP '^From: *\K.*'
Here is a Bash one-liner:
grep ^From file.txt | while read -a cols; do echo ${cols[#]:1}; done
See: Handling positional parameters at wiki.bash-hackers.org
cut itself is a very handy tool in bash
cut -d (delimiter character) -f (fields that you want as output)
a single field is given directly as -f 3 ,
range of fields can be selected as -f 5-9
so in your this particular case code would be
egrep '^From:' $file | cut -d\ -f 2-3
the delimiter is space here and can be escaped using a \
-f 1 corresponds to " From " and 2-3 corresponds to " First Last "

what does grep -v '^#' do

My program looks like this.
ALL=`cat $1 | grep -v '^#' | wc -l`
FINISHED="0"
for i in `cat $1 | grep -v '^#'`; do
echo "PROBE $i"
I will be doing some operation
FINISHED=`echo $FINISHED"+1"|bc`
I will run this script by giving a file name as parameter where a list of probes will be present.
I have 2 questions
What does grep -v '^#' mean. I learnt that '^ is usually used to matching a particular string. But in the file name which I give there is no #. Moreover I am getting the total number of probes for cat $1 | grep -v '^#' | wc -l.
echo $FINISHED"+1"|bc. Here any idea as to why the developer as added |bc?
^ means "start of line"
# is the literal character #
-v means "invert the match" in grep, in other words, return all non matching lines.
Put those together, and your expression is "select all lines that do not begin with #"
| is the pipe character, it takes the output of the command on the left hand side, and uses it as the input of the command on the right hand side. bc is like a command line calculator (to do basic math).
I would use this to exclude comments from the code I'm reading. So all comment lines start with # and I don't want to see them if there are too many of them.
grep -v '^#'
We have different ways for calculation. Pick the one which you like.
a=`echo 1+1 | bc`; echo $a
b=$((1+1)); echo $b
c=`expr 1 + 1`; echo $c
let d=1+1; echo $d

Resources