3

if I have a script like this:

#!/bin/bash
echo `script2.sh` > temp.txt &
(wait for long enough time)
a=`cat temp.txt`
echo $a

a's value will be successfully changed by script2.sh. However, if I do this:

#!/bin/bash
a=`script2.sh` &
(wait for long enough time)
echo $a

a's value would not be changed by script2.sh. The reason why I want to do this is becasue:(1)I do not want the main process to be blocked by the script2.sh(during waiting,I can do something else) (2)My main program will do a lot of such stuff, so doing a lot of file IOs will give me a big overhead and it's better to directly assign the value to a variable in memory. I have found the file IO in bash script is really very slow. In my program,doing 400 such IOs will take about 10 seconds (when the computer is busy though)! Any suggestion?

Hao Shen
  • 2,605
  • 3
  • 37
  • 68
  • Maybe this SO answer[1] can help you. [1]: http://stackoverflow.com/questions/690266/why-cant-i-use-job-control-in-a-bash-script – Martz Aug 18 '13 at 01:08
  • See this related question: http://stackoverflow.com/questions/15696382/bash-how-to-get-variable-from-the-script-that-runs-in-the-background. It would appear that a temp file may be your best option. – lurker Aug 18 '13 at 01:08
  • 1
    I should mention that I tried `(export a=\`script2.sh\`)&` and that didn't work either. – lurker Aug 18 '13 at 01:11

1 Answers1

2

You can't assign a shell variable to a value that doesn't exist yet, so your approach simply isn't possible. I don't see a realistic option other than a temp file, but you can speed that option up quite a bit. I'm pretty sure it's not the file I/O that's slow, it's that you're creating a subshell to echo the script's output to the file, and a cat process to read the file. Process creation is slow, so if you want speed that's important to minimize. You can avoid creating the echo subprocess by redirecting the shell's output directly to the file, and replace the cat process with a bash's $(<file) idiom that reads the file directly in the shell. Here's what I came up with:

#!/bin/bash
script2.sh >temp.txt &
# (wait for long enough time)
a=$(<temp.txt)
echo "$a"
Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • Thanks for your suggestion. I have tested. You are right. Original way(using cat) will take about 17.5 seconds for my program. Your way will take about 7.5 seconds. However, if I directly use a concrete value instead of getting it from a file, it takes only about 1 second.I will adopt your way to avoid creating sub-processes. (BTW,I also use "eval" in my script.It will not create sub-process,right?) – Hao Shen Aug 18 '13 at 02:04
  • `eval` won't necessarily create a subprocess, but it really depends on exactly how it's used. As a test, try replacing the `eval` section with something simple that clearly doesn't create any processes, and see how fast that runs. Also, is there anything else you're doing in each of those 400 instances that might create a process, like using `ps` to see if a backgrounded script has finished, or using `rm` to remove a temp file, or... – Gordon Davisson Aug 18 '13 at 02:23
  • In my eval, I just do some simple math:> Like: eval 'a=$b+ `cat temp.txt`' I think if I remove the "cat", eval will not create process in my situation. – Hao Shen Aug 18 '13 at 02:26
  • `eval` doesn't do math, it executes commands; if $b is set to "3" and temp.txt contains "5", the `eval` command you gave will set $a to the string "3+5", not 8. To do math in bash, use the `let` command, or double-parentheses: `(( a=b+$( – Gordon Davisson Aug 18 '13 at 04:56
  • Thanks a lot for your reply. I used eval for a reason:http://stackoverflow.com/questions/18222779/in-bash-how-to-use-a-variable-as-part-of-the-name-of-another-variable – Hao Shen Aug 18 '13 at 14:08
  • 1
    I'd actually recommend indirect expansion (Vaughn Cato's answer) instead of `eval` in cases like that. `eval` has so many ways to cause problems I have a hard time trusting anything using it. – Gordon Davisson Aug 18 '13 at 16:01