2

Let's suppose I have a bash script (foo.sh) that in a very simplified form, looks like the following:

echo "hello"
sleep 100 &
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
echo "bye"

The third line imitates pkill, which I don't have by default on Mac OS X, but you can think of it as the same as pkill. However, when I run this script, I get the following output:

hello
foo: line 4: 54851 Killed                  sleep 100
bye

How do I suppress the line in the middle so that all I see is hello and bye?

Chris Bunch
  • 87,773
  • 37
  • 126
  • 127

5 Answers5

14

While disown may have the side effect of silencing the message; this is how you start the process in a way that the message is truly silenced without having to give up job control of the process.

{ command & } 2>/dev/null

If you still want the command's own stderr (just silencing the shell's message on stderr) you'll need to send the process' stderr to the real stderr:

{ command 2>&3 & } 3>&2 2>/dev/null

To learn about how redirection works:

And by the way; don't use kill -9.

I also feel obligated to comment on your:

ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9

This will scortch the eyes of any UNIX/Linux user with a clue. Moreover, every time you parse ps, a fairy dies. Do this:

kill $!

Even tools such as pgrep are essentially broken by design. While they do a better job of matching processes, the fundamental flaws are still there:

  • Race: By the time you get a PID output and parse it back in and use it for something else, the PID might already have disappeared or even replaced by a completely unrelated process.
  • Responsibility: In the UNIX process model, it is the responsibility of a parent to manage its child, nobody else should. A parent should keep its child's PID if it wants to be able to signal it and only the parent can reliably do so. UNIX kernels have been designed with the assumption that user programs will adhere to this pattern, not violate it.
Community
  • 1
  • 1
lhunath
  • 120,288
  • 16
  • 68
  • 77
  • Great, thanks for the links! I'm checking them out now, but your first code snippet doesn't produce the intended output (at least not on OSX). The second one works as expected though. – Chris Bunch Apr 03 '09 at 18:28
  • @lhunath — i thought `pgrep`/`pkill` *were* the skillful replacements for parsing `ps`. could you elaborate more on what's "broken" about them? i appreciate distinctions between different approaches and would be interested in details on this one. – RubyTuesdayDONO Feb 19 '14 at 17:26
3

How about disown? This mostly works for me on Bash on Linux.

echo "hello"
sleep 100 &
disown
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
echo "bye"

Edit: Matched the poster's code better.

JasonSmith
  • 72,674
  • 22
  • 123
  • 149
  • Of course, if you do this then you lose job control, so you can't do kill %1 or whatever later. I'm not sure if you can get away with that but in most cases you probably can. These days if you're getting into fancy job control you'll be in Perl or whatever. – JasonSmith Apr 03 '09 at 17:43
  • Great, that seems to do it! I'll look into the implications of losing job control with my app but it should be fine. Thanks! – Chris Bunch Apr 03 '09 at 17:47
1

The message is real. The code killed the grep process as well.

Run ps ax | grep sleep and you should see your grep process on the list.

What I usually do in this case is ps ax | grep sleep | grep -v grep

EDIT: This is an answer to older form of question where author omitted the exclusion of grep for the kill sequence. I hope I still get some rep for answering the first half.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • Yes, I'm aware of that, and that's fine with me. But what I'm looking for is a way to supress the messages on the second and third lines. Thanks though! – Chris Bunch Apr 03 '09 at 17:23
  • Yes, I had made the change to include your suggestion to omit grep from the list of things to kill, but that wasn't the point of the question. I was just looking for a way to suppress the output, not to omit "grep sleep" from the list. – Chris Bunch Apr 04 '09 at 20:16
0

Yet another way to disable job termination messages is to put your command to be backgrounded in a sh -c 'cmd &' construct.

And as already pointed out, there is no need to imitate pkill; you may store the value of $! in another variable instead.

echo "hello"
sleep_pid=`sh -c 'sleep 30 & echo ${!}' | head -1`
#sleep_pid=`sh -c '(exec 1>&-; exec sleep 30) & echo ${!}'`
echo kill $sleep_pid
kill $sleep_pid
echo "bye"
phily
  • 9
  • 1
  • it doesn't work at least for bash 4.1.5(1) and dash 0.5.5.1: outer shell waits for sleep to terminate – x-yuri May 24 '13 at 14:16
-1

Have you tried to deactivate job control? It's a non-interactive shell, so I would guess it's off by default, but it does not hurt to try... It's regulated by the -m (monitor) shell variable.

Varkhan
  • 16,601
  • 5
  • 31
  • 24