8

I have function where I am expecting it to hang sometime. So I am setting one global variable and then reading it, if it didn't come up after few second I give up. Below is not complete code but it's not working as I am not getting $START as value 5

START=0
ineer()
{
    sleep 5
    START=5
    echo "done $START"   ==> I am seeing here it return 5
    return $START
}
echo "Starting"
ineer &

while true
do
    if [ $START -eq 0 ]
    then
        echo "Not null $START"  ==> But $START here is always 0
    else
        echo "else $START"
        break;
    fi
    sleep 1;
done
4
  • 7
    I suspect that running the function in the background causes it to be executed in a subshell, so the variable changes are not reflected in the parent shell. Commented Apr 16, 2015 at 17:33
  • timeout is exact fit for me but It did't take function as command Commented Apr 16, 2015 at 17:35
  • 3
    You may be interested in unix.stackexchange.com/questions/87284/… -- mind you, @user000001 is exactly right that ineer is executed in a subshell and doesn't share an environment with its parent shell, so what you're going to find there are workarounds (mostly involving files). Commented Apr 16, 2015 at 17:36
  • You might need to look at the timeout command from GNU coreutils. You may also end up looking at signals (trap and kill) between child and parent processes. Commented Apr 16, 2015 at 17:40

4 Answers 4

12

You run inner function call in back ground, which means the START will be assigned in a subshell started by current shell. And in that subshell, the START value will be 5.

However in your current shell, which echo the START value, it is still 0. Since the update of START will only be in the subshell.

Each time you start a shell in background, it is just like fork a new process, which will make a copy of all current shell environments, including the variable value, and the new process will be completely isolate from your current shell.

Since the subshell have been forked as a new process, there is no way to directly update the parent shell's START value. Some alternative ways include signals passing when the subshell which runs inner function exit.

common errors:

export

export could only be used to make the variable name available to any subshells forked from current shell. however, once the subshell have been forked. The subshell will have a new copy of the variable and the value, any changes to the exported variable in the shell will not effect the subshell.

Please take the following code for details.

#!/bin/bash
export START=0
ineer()
{
    sleep 3
    export START=5
    echo "done $START"  # ==> I am seeing here it return 5
    sleep 1
    echo "new value $START"
    return $START
}
echo "Starting"
ineer &

while true
do
    if [ $START -eq 0 ]
    then
        echo "Not null $START" #  ==> But $START here is always 0
        export START=10
        echo "update value to $START"
        sleep 3
    else
        echo "else $START"
        break;
    fi
    sleep 1;
done
Sign up to request clarification or add additional context in comments.

Comments

2

The problem is that ineer & runs the function in a subshell, which is its own scope for variables. Changes made in a subshell will not apply to the parent shell. I recommend looking into kill and signal catching.

Comments

1

Save pid of inner & by:

pid=$!

and use kill -0 $pid (that is zero!!) to detect if your process still alive.

But better redesign inner to use lock file, this is safer check!

UPDATE From KILL(2) man page:

  #include <sys/types.h>
  #include <signal.h>

  int kill(pid_t pid, int sig);

If sig is 0, then no signal is sent, but error checking is still
performed; this can be used to check for the existence
of a process ID or process group ID.

1 Comment

Can you add more on this use kill -0 $pid (that is zero!!)
-1

The answer is: in this case you can use export. This instruction allow all subprocesses to use this variable. So when you'll call the ineer function it will fork a process that is copying the entire environment, including the START variable taken from the parent process.

You have to change the first line from:

START=0

to:

export START=0

You may also want to read this thread: Defining a variable with or without export

1 Comment

export does not work, as it does not effect the subshell once the subshell have already been forked.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.