0

I have a bash script (this_script.sh) that invokes multiple instances of another TCL script.

set -m
for vars in $( cat vars.txt );
do
   exec tclsh8.5 the_script.tcl "$vars" &
done
while [ 1 ]; do fg 2> /dev/null; [ $? == 1 ] && break; done

The multi threading portion was taken from Aleksandr's answer on: Forking / Multi-Threaded Processes | Bash. The script works perfectly (still trying to figure out the last line). However, this line is always displaed: exec tclsh8.5 the_script.tcl "$vars"

How do I hide that line? I tried running the script as :

bash this_script.sh > /dev/null

But this hides the output of the invoked tcl scripts too (I need the output of the TCL scripts). I tried adding the /dev/null to the end of the statement within the for statement, but that too did not work either. Basically, I am trying to hide the command but not the output.

Community
  • 1
  • 1
user2883071
  • 960
  • 1
  • 20
  • 50
  • 3
    Why aren't you using `wait` instead? – Ignacio Vazquez-Abrams Mar 12 '15 at 15:41
  • 1
    `for vars in $( – kojiro Mar 12 '15 at 15:47
  • 2
    Alternative to `wait`, you could use [GNU parallel](https://www.gnu.org/software/parallel/) or even just `xargs` to run in parallel. (BTW, that's not multi-threading, it's just multiple processes.) – kojiro Mar 12 '15 at 15:47
  • Is `exec` doing anything for you here? Reading values from a file like that isn't safe (http://mywiki.wooledge.org/DontReadLinesWithFor). Where is that line showing? When the processes end? – Etan Reisner Mar 12 '15 at 15:48
  • As soon as the script starts, it shows that line. If I don't use exec, then this still shows: `tclsh8.5 the_script.tcl "$vars"` – user2883071 Mar 12 '15 at 15:54
  • That exact script (well with `exec` replaced by `:`) prints nothing here. Does the printed line have a `+` in front of it? Are you using `set -x` anywhere? – Etan Reisner Mar 12 '15 at 16:04
  • It works now, I took the exec out. Implementing Donal's answer fixed it – user2883071 Mar 12 '15 at 18:19

1 Answers1

1

You should use $! to get the PID of the background process just started, accumulate those in a variable, and then wait for each of those in turn in a second for loop.

set -m
pids=""
for vars in $( cat vars.txt ); do
   tclsh8.5 the_script.tcl "$vars" &
   pids="$pids $!"
done
for pid in $pids; do
   wait $pid
   # Ought to look at $? for failures, but there's no point in not reaping them all
done
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • 2
    Why `wait` individually instead of all at once with `wait` by itself? – Etan Reisner Mar 12 '15 at 15:48
  • when I use this method, the script starts off with the message: `this_script.sh: line 15: pids: command not found` – user2883071 Mar 12 '15 at 16:00
  • 2
    @user2883071 Did you use `pid =` (with the space) somewhere? – Etan Reisner Mar 12 '15 at 16:01
  • I have not used it that way anywhere, I typed it out the exact same way. However, even though I get that message, the script still works. HOWEVER, another issue comes up. once the script has finish, it halts on a blank line (so the user will not know if it is still running or not). The way I fixed this earlier was by implementing Aleksandrs method. – user2883071 Mar 12 '15 at 16:04
  • 1
    @user2883071 If you have `pids=` everywhere then you shouldn't see that "command not found" error. There also aren't 15 lines in that snippet so which is line 15 for you? – Etan Reisner Mar 12 '15 at 16:05
  • @EtanReisner WAIT, found something – user2883071 Mar 12 '15 at 16:09
  • Sorry, I forgot the `!`. It works now. I have a few questions about how it works though, 1) why is it that Aleksandrs way of doing it is not that efficient? 2) in the solution here, when the multiple threads are initiated, why doesn't the `pids` only take the last process pid? aren't they all instantiated at the same time? – user2883071 Mar 12 '15 at 16:17