2

Have a relatively simple question here. I need to run a function in the background in bash. Normally I would do it just like so:

FUNCTION &

but things are a bit more complicated than that. I have the following line that runs the main function for each record in a text database. I cant really edit this code all that much without vastly changing the rest of the entire project, but im still open to new ideas.

cat databases/$WAN | grep -v \# | while read LINE; do MAIN; done

I want to spawn a new terminal in background for each record to do a sort of parallel type processing, making things go much faster. Main takes a minute to process for each record. This however does not work.

cat databases/$WAN | grep -v \# | while read LINE; do MAIN &; done

Any suggestions?

* UPDATE *

Thanks for all the responses. Let me see if I can answer some of those questions.

gniourf_gniourf - Yes I know using cat like this is wrong. This was early on, and critical code, so I have not updated it yet. I now read into the while loop for most things I do. I will fix it eventually. You may be right about syntax. When I break it up like so, things seem to work now:

  cat databases/$WAN | grep -v \# | while read LINE
  do
    MAIN & > /dev/null 2>&1
  done

So that fixes the background problem. I wonder what was messed up in my single line syntax. Thanks

chepner - I don't believe LINE is a variable. I could be wrong though. Some things about Bash still confuse me. Maybe it is and is a variable that the entire record from the database gets stored to prior to processing.

Bruce K - Waiting is exactly what I was trying to avoid. If I let it run in the same terminal one at a time, it will slowly process each record in order. If I push each record to a seperate terminal for processing, all records will be processed simultaneously (at least in our eyes). The additional overhead is intentional in order to speed up how quickly the loop through the database occurs.

Radix - Yes you're right. I'll read up on that. Thanks for the link.

Atomiklan
  • 5,164
  • 11
  • 40
  • 62
  • 3
    What do you mean by _does not work_? you clearly have a syntax error: remove the semi colon after the ampersand. (and useless use of `cat`). – gniourf_gniourf Apr 29 '14 at 17:16
  • 1
    Does `MAIN` use `LINE` as a global variable? You'll have to either export `LINE` before running `MAIN` in the background or pass `LINE` as an argument to `MAIN` (and modifying the function to accept the argument). – chepner Apr 29 '14 at 17:35
  • A new terminal is a lot of overhead. Essentially, you want to collect the stdout from each? Then include a counter in the loop and use it within "MAIN" to redirect stdin and stdout ("exec 1>log$ct 2>err$ct") wait for all to finish and cat out the results. – Bruce K Apr 29 '14 at 17:49
  • Seems like this question is a duplicate of http://stackoverflow.com/questions/1455695/forking-multi-threaded-processes-bash ? – Ciano Apr 29 '14 at 17:50
  • @atomiklan, both `&` and `;` are command terminators -- putting more than one side-by-side is the error ([ref](http://www.gnu.org/software/bash/manual/bashref.html#Simple-Commands) -- "terminated by *one of* ..."). Consider `sleep 1 &; echo syntax error` versus `sleep 1 & echo good` – glenn jackman Apr 29 '14 at 19:04

1 Answers1

2

This worked for me:

$ function testt(){ echo "lineee is <$lineee>";}
$ grep 5432 /etc/services|while read lineee;do testt&done
lineee is <postgres     5432/udp                        # POSTGRES>
lineee is <postgres     5432/tcp                        # POSTGRES>

If, for some reason, your MAIN function is not seeing a LINE variable, you can try:

"export" the LINE variable beforehand:

$ export LINE
$ # do your thing

Or, pass the line read as an argument to the function:

$ function testt(){ LINE="$1"; echo "LINE is <$LINE>";}
$ grep 5432 /etc/services|while read LINE;do testt "$LINE"&done
aqn
  • 2,542
  • 1
  • 16
  • 12