1

I'm creating a script to update a remote computer and I want to know if any user is using the computer before I update. I have a list of users and I created a heredoc with all of them. The command I'm trying to make look something like this:

ps -ef | grep -f | cat <<- END
    user1
    user2
    user3
END

Which doesn't work. What can I do to be able to filter the ps command based on my user list using a heredoc?

2 Answers2

4

Short answer: ps -u user1,user2,user3


Your grep command is incomplete since the -f option requires an argument. Your cat command is receiving its input from the here document, so even if you fixed the grep command, its output would be discarded.

If you were looking for a hard-coded user, you'd use

ps -ef | grep alice

(except that this isn't a good way to do it as I'll explain later). The input to grep is the output of ps -ef. You can pass multiple search patterns by passing multiple -e options:

ps -ef | grep -e alice -e bob

This prints lines containing alice or bob. To get the list of inputs from a file, you can use the -f option, but that requires a file name.

cat <<EOF >users.txt
alice
bob
END
ps -ef | grep -f users.txt

Standard input is already taken for the text that you're filtering, so you can't reuse it for the search pattern. Wanting multiple inputs is a common problem, so some shells (ksh, bash, zsh) offer a solution: process substitution (which is what don_crissti suggested in a comment):

ps -ef | grep -f <(cat <<END
alice
bob
END
)

This approach is useful if the list of users is generated by a complex command, but with a hard-coded list, it's unnecessarily complex: grep -e alice -e bob does the same job.


The problem with this approach is that it matches user names anywhere on the line. The ps command has an option to list only the processes of a specific set of users. Just use that.

ps -u alice,bob

If you're on an embedded system with a version of ps that doesn't support -u, see if it supports -o USER, and use grep -x to match the whole line.

busybox ps -o user | grep -x -e alice -e bob
1

In general I would recommend the answer by Gilles.

If you need your script to be POSIX compatible and your ps does not support -u, this could work:

ps -ef | grep -e \
"^smtpd
^dbus
^ntp"

I.e. pipe the output of ps -ef through grep -e pattern_list. The pattern_list is supplied as a multiline-string, each pattern starts with ^ to anchor it at the beginning of a line.

johnLate
  • 3,034