How to combine output from awk and pipe into htop? - bash

$ ps -ef | grep python | awk -F' ' '{print $2}'
9825
4470
4619
$ htop -p 9825,4470,4619
For now, I have to make two separate commands in order to watch all python processes within htop. Is there a way that I can pipe all the results from awk and feed them into htop?

If you have pgrep (you probably do):
htop -p $(pgrep python | paste -sd,)

You could avoid grep and use only awk using something like:
ps -ef | awk '/[p]ython/{print $2}'
Then you could use:
htop -p $(ps -ef | awk -v ORS=, '/[p]ython/{print $2}')
Notice the [] around the p, this is a nice trick to avoid printing the second command itself:
ps -ef | awk '/[p]ython/{print $2}'
| |
cmd 1 cmd 2
it works because awk will translate the regex [p] to say something like "match characters from [p] in this case, p only, followed by ython:
[p]ython != python

Related

Multiple output in single line Shell commend with pipe only

For example:
ls -l -d */ | wc -l | awk '{print $1}' | tee /dev/tty | ls -l
This shell command print the result of wc and ls -l with single line, but tee is used.
Is it possible to using one Shell commend line to achieve multiple output without using “&&” “||” “>” “>>” “<” “;” “&”,tee and temp file?
When you want the output of date and ls -rtl | head -1 on one line, you can use
echo "$(date): $(ls -rtl | head -1)"
Yes, you can achieve writing to multiple files with awk which is not in the list of things you appear not to like:
echo hi | awk '{print > "a.txt"; print > "b.txt"}'
Then check a.txt and b.txt.

How to get commands and arguments from ps command

I want to parse the output of a ps -ef command in order to display the command names and their arguments. I have two options that will display the command names:
ps -ef | awk '{print $8}'
or
ps -efo comm
However, neither of these will also display the arguments. Is there a way to do this without doing
ps -ef | awk '{print $8 $9 $10 ....}'
?
You can use ps like this:
ps -eo command

bash command quoted by single quote

I need to find process by string matching, and the kill it, need to do it in one line in another script file:
here's what I tried:
'kill $(ps -ef|grep xxx|grep -v grep | awk '{print $2 }' )'
"kill $(ps -ef|grep xxx|grep -v grep | awk '{print $2 }' )"
first one didn't work because of the nested single quote, second one didn't work because $2 is taken by the parent script to be argument 2 to parent script.
how do I do this?
The easiest way to accomplish that task is:
pkill xxx
(which you'll find in the debian/ubuntu world in package procps, if you don't have it installed.) You might need to use pkill -f xxx, depending on whether xxx is part of the process name or an argument, which is often the case with script execution.
However, to answer the more general question about shell-quoting, if you need to pass the string
kill $(ps aux | grep xxx | grep -v grep | awk '{print $2}')
as an argument, you need to use backslash escapes:
bash -c "kill \$(ps aux | grep xxx | grep -v grep | awk '{print \$2}')"
Or, you can paste together several quoted strings:
bash -c 'kill $(ps aux | grep xxx | grep -v grep | awk '"'"'{print $2}'"'"')'
Personally, I find the first one more readable but YMMV.
You can only backslash escape a few characters inside a double-quoted string: $, ", \, newline and backtick; and inside a single-quoted string backslash is just backslash. However, that's enough to let you type just about anything.

ps aux | grep returns pid for itself too

I am using this command to get the process ID of another command:
ps aux | grep 7000.conf | awk '{print $2}'
This will return two PIDs:
7731
22125
I only want the first one. The second is the PID for grep in the above command. Thanks in advance to any one who knows how to alter the above command to return just the first pid.
p.s. open to a new command that does the same thing
In this particular case, escaping the . to what I assume it was meant to do should work:
ps aux | grep '7000\.conf' | awk '{print $2}'
Alternatively, exclude grep:
ps aux | grep 7000.conf | grep -v grep | awk '{print $2}'
ps aux | grep "[7]000.conf" will work as well.

How to get process id from process name?

I'm trying to create a shell script getting the process id of the Skype app on my Mac.
ps -clx | grep 'Skype' | awk '{print $2}' | head -1
The above is working fine, but there are two problems:
1)
The grep command would get all process if their name just contains "Skype". How can I ensure that it only get the result, if the process name is exactly Skype?
2)
I would like to make a shell script from this, which can be used from the terminal but the process name should be an argument of this script:
#!/bin/sh
ps -clx | grep '$1' | awk '{print $2}' | head -1
This isn't returning anything. I think this is because the $2 in the awk is treated as an argument too. How can I solve this?
Your ps -cl1 output looks like this:
UID PID PPID F CPU PRI NI SZ RSS WCHAN S ADDR TTY TIME CMD
501 185 172 104 0 31 0 2453272 1728 - S ffffff80145c5ec0 ?? 0:00.00 httpd
501 303 1 80004004 0 31 0 2456440 1656 - Ss ffffff8015131300 ?? 0:11.78 launchd
501 307 303 4004 0 33 0 2453456 7640 - S ffffff8015130a80 ?? 0:46.17 distnoted
501 323 303 40004004 0 33 0 2480640 9156 - S ffffff80145c4dc0 ?? 0:03.29 UserEventAgent
Thus, the last entry in each line is your command. That means you can use the full power of regular expressions to help you.
The $ in a regular expression means the end of the string, thus, you could use $ to specify that not only does the output must have Skype in it, it must end with Skype. This means if you have a command called Skype Controller, you won't pull it up:
ps -clx | grep 'Skype$' | awk '{print $2}' | head -1
You can also simplify things by using the ps -o format to just pull up the columns you want:
ps -eo pid,comm | grep 'Skype$' | awk '{print $1}' | head -1
And, you can eliminate head by simply using awk's ability to select your line for you. In awk, NR is your record number. Thus you could do this:
ps -eo pid,comm | grep 'Skype$' | awk 'NR == 1 {print $1}'
Heck, now that I think of it, we could eliminate the grep too:
ps -eo pid,comm | awk '/Skype$/ {print $1; exit}'
This is using awk's ability to use regular expressions. If the line contains the regular expression, 'Skype$', it will print the first column, then exit
The only problem is that if you had a command Foo Skype, this will also pick it up. To eliminate that, you'll have to do a bit more fancy footwork:
ps -eo pid,comm | while read pid command
do
if [[ "$command" = "Skype" ]]
then
echo $pid
break
fi
done
The while read is reading two variables. The trick is that read uses white space to divide the variables it reads in. However, since there are only two variables, the last one will contain the rest of the entire line. Thus if the command is Skype Controller, the entire command will be put into $command even though there's a space in it.
Now, we don't have to use a regular expression. We can compare the command with an equality.
This is longer to type in, but you're actually using fewer commands and less piping. Remember awk is looping through each line. All you're doing here is making it more explicit. In the end, this is actually much more efficient that what you originally had.
If pgrep is available on Mac, you can use pgrep '^Skype$'. This will list the process id of all processes called Skype.
You used the wrong quotes in your script:
ps -clx | grep "$1" | awk '{print $2}' | head -1
or
pgrep "^$1$"
The problem with your second example is that the $1 is in single quotes, which prevents bash from expanding the variable. There is already a utility that accomplishes what you want without manually parsing ps output.
pgrep "$1"
You can do this in AppleScript:
tell application "System Events"
set skypeProcess to the process "Skype"
set pid to the unix id of skypeProcess
pid
end tell
which means you can use 'osascript' to get the PID from within a shell script:
$ osascript -e "tell application \"System Events\"" -e "set skypeProcess to the process \"Skype\"" -e "set pid to the unix id of skypeProcess" -e "pid" -e "end tell"
3873
You can format the output of ps using the -o [field],... and list by process name using -C [command_name] ;however, ps will still print the column header, which can be removed by piping it through grep -v PID
ps -o pid -C "$1" |grep -v PID
where $1 would be the command name (in this case Skype)
I'd so something like:
ps aux | grep Skype | awk 'NR==1 {print $2}'
==== UPDATE ====
Use the parameter without quotes and use single quotes for awk
#!/bin/bash
ps aux | grep $1 | awk 'NR==1 {print $2}'
Method 1 - Use awk
I don't see any reason to use the -l flag (long format), I also don't see any reason to use grep and awk at the same time: awk has grep capability built in. Here is my plan: use ps and output just 2 columns: pid and command, then use awk to pick out what you want:
ps -cx -o pid,command | awk '$2 == "Skype" { print $1 }'
Method 2 - Use bash
This method has the advantage that if you already script in bash, you don't even need awk, which save one process. The solution is longer than the other method, but very straight forward.
#!/bin/bash
ps -cx -o pid,command | {
while read pid command
do
if [ "_$command" = "_$1" ]
then
# Do something with the pid
echo Found: pid=$pid, command=$command
break
fi
done
}
pgrep myAwesomeAppName
This works great under Catalina 10.15.2
Use double quotes to allow bash to perform variable substitution.
Single quotes disable bash variable substitution mechanism.
ps -clx | grep "$1" | awk "{print $2}" | head -1

Resources