4

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.

lpf
  • 73
  • 1
  • 6
  • 1
    I don't think that's possible without named pipes (or some eval hack, which is widely frowned upon for good reasons). Besides all POSIX-compliant systems implement them, what makes you think that *[n]amed pipes seem difficult to use portably and safely.*? – oguz ismail Jun 22 '20 at 12:09
  • 1
    I've read that mktemp isn't specified by POSIX, and that signal handling (to clean up in case of kill/hang) can also be problematic, so I don't know what method to use that I can feel confident in. – lpf Jun 22 '20 at 12:15
  • meta comment : Note the low number of watchers for most of your tags. Tags on S.O. are best used to attract watchers of specific topics. You may hate to use `[bash]` but you'll get 2X eyes on your Q. `bash` is now a reasonable assumption to be available (IMO). Generally speaking, this level of discussion/topic is pretty rare here. Maybe search archives of comp.unix.shell (where I do remember seeing such discussions) will get you some more ideas. And consider using a language that has fewer issues with buffering. `gawk` and `perl` are generally available everywhere. Good luck! – shellter Jun 22 '20 at 15:14

1 Answers1

3

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"
chepner
  • 497,756
  • 71
  • 530
  • 681