Search code examples
shellscopeevent-handlingposixsubshell

In POSIX sh, how to preserve variables set in a 'while read' loop when the input is continuous (event watcher)?


If you don't need to set global variables, or are willing to use named pipes, you can use:

$NAMED_PIPE="/tmp/mypipe"
mkfifo $NAMED_PIPE

command | # piped into while read, command can be an event watcher
    while read -r foo bar; do
        MY_VAR="$foo"
        echo "$MY_VAR" # This works
        echo "MY_VAR" > "$NAMED_PIPE" &
    done

echo "$MY_VAR" # This doesn't work
cat "$NAMED_PIPE" # This works

If you need to set global variables, you can use the following in bash:

while read -r foo bar; do
    MY_VAR="$foo"
    echo "$MY_VAR" # This works
done < <(command) # command can be an event watcher

echo "$MY_VAR" # This works

In POSIX sh, you can do the following, but it doesn't work with continuous input (seems to just hang):

while read -r foo bar; do
    MY_VAR="$foo"
    echo "$MY_VAR" # Works as long as command doesn't produce continuous output
done <<-EOF
$(command) 
EOF

echo "$MY_VAR" # Works as long as command doesn't produce continuous output

Is there a solid way to parse an event watcher (e.g. xev, xprop -spy) in POSIX sh and be able to set global variables? Named pipes seem difficult to use portably and safely.


Solution

  • The named pipe is the solution, but you are using it in the wrong place.

    NAMED_PIPE="/tmp/mypipe"
    mkfifo "$NAMED_PIPE"
    
    command > "$NAMED_PIPE" &
    
    while read -r foo bar; do
        MY_VAR="$foo"
        echo "$MY_VAR"
    done < "$NAMED_PIPE"
    
    echo "$MY_VAR"