Bash "&" Without Printing "[1]+ Done "

bash & without printing [1]+ Done

That message isn't coming from mailcheck, it's from bash's job control telling you about your backgrounded job. The way to avoid it is to tell bash you don't want it managed by job control:

mailcheck &
disown $!

Execute process in background, without printing Done, and get PID

Solution A

When summoning the process, redirect the shell's stderr to >/dev/null for that summoning instance. We can do this by duplicating fd 2 so we could still use the duplicate fd for the process. We do all of these inside a block to make redirection temporary:

{ sleep 5 2>&3 & pid=$!; } 3>&2 2>/dev/null

Now to prevent the "Done" message from being shown later, we exclude the process from the job table and this is done with the disown command:

{ sleep 5 2>&3 & disown; pid=$!; } 3>&2 2>/dev/null

It's not necessary if job control is not enabled. Job control can be disabled with set +m or shopt -u -o monitor.

Solution B

We can also use command substitution to summon the process. The only problem we had is that the process still hooks itself to the pipe created by $() that reads stdout but we can fix this by duplicating original stdout before it then using that file descriptor for the process:

{ pid=$( sleep 200s >&3 & echo $! ); } 3>&1

It may not be necessary if we redirect the process' output somewhere like /dev/null:

pid=$( sleep 200s >/dev/null & echo $! )

Similarly with process substitution:

{ read pid < <(sleep 200s >&3 & echo $!); } 3>&1

Some may say that redirection is not necessary for process substitution but the problem is that the process that may be accessing its stdout would die quickly. For example:

$ function x { for A in {1..100}; do echo "$A"; sleep 1s; done }
$ read pid < <(x & echo $!)
$ kill -s 0 "$pid" &>/dev/null && echo "Process active." || echo "Process died."
Process died.
$ read pid < <(x > /dev/null & echo $!)
$ kill -s 0 "$pid" &>/dev/null && echo "Process active." || echo "Process died."
Process active.
  • Optionally you can just create a permanent duplicate fd with exec 3>&1 so you can just have pid=$( sleep 200s >&3 & echo $! ) on the next lines.

Bash set +x without it being printed

I had the same problem, and I was able to find a solution that doesn't use a subshell:

set -x
command
{ set +x; } 2>/dev/null

Running bash commands in the background without printing job and process ids

Not related to completion, but you could supress that output by putting the call in a subshell:

(echo "Hello I'm a background task" &)

how to print no. from n to 1 from the pattern in shell script

The immediate error is that your requirement calls for subtracting two items from the start in each iteration, but you only subtract one.

More generally, probably avoid echo -e entirely; learn to use printf if you need detailed control over newlines etc.

for ((a=$rows; a>=1; a-=2)); do
printf -v sep "%$((rows - a))s" ""
for ((b=$a; b>=1; b--)); do
printf "%s%i" "$sep" "$b"
sep=" "
done
printf '\n'
done

And, as demonstrated here, probably learn to indent your code to show how blocks are nested.

Tangentially, perhaps better to accept the number of rows as a command-line argument rather than prompt interactively for a value. Interactive I/O is pesky when you want to use your script as part of another larger script.

Find and kill a process in one line using bash and regex

In bash, you should be able to do:

kill $(ps aux | grep '[p]ython csp_build.py' | awk '{print $2}')

Details on its workings are as follows:

  • The ps gives you the list of all the processes.
  • The grep filters that based on your search string, [p] is a trick to stop you picking up the actual grep process itself.
  • The awk just gives you the second field of each line, which is the PID.
  • The $(x) construct means to execute x then take its output and put it on the command line. The output of that ps pipeline inside that construct above is the list of process IDs so you end up with a command like kill 1234 1122 7654.

Here's a transcript showing it in action:

pax> sleep 3600 &
[1] 2225
pax> sleep 3600 &
[2] 2226
pax> sleep 3600 &
[3] 2227
pax> sleep 3600 &
[4] 2228
pax> sleep 3600 &
[5] 2229
pax> kill $(ps aux | grep '[s]leep' | awk '{print $2}')
[5]+ Terminated sleep 3600
[1] Terminated sleep 3600
[2] Terminated sleep 3600
[3]- Terminated sleep 3600
[4]+ Terminated sleep 3600

and you can see it terminating all the sleepers.


Explaining the grep '[p]ython csp_build.py' bit in a bit more detail:

When you do sleep 3600 & followed by ps -ef | grep sleep, you tend to get two processes with sleep in it, the sleep 3600 and the grep sleep (because they both have sleep in them, that's not rocket science).

However, ps -ef | grep '[s]leep' won't create a process with sleep in it, it instead creates grep '[s]leep' and here's the tricky bit: the grep doesn't find it because it's looking for the regular expression "any character from the character class [s] (which is s) followed by leep.

In other words, it's looking for sleep but the grep process is grep '[s]leep' which doesn't have sleep in it.

When I was shown this (by someone here on SO), I immediately started using it because

  • it's one less process than adding | grep -v grep; and
  • it's elegant and sneaky, a rare combination :-)


Related Topics



Leave a reply



Submit