3

I'm using this command format:

cmd0 > >(cmd1) 2> >(cmd2)

Cmd2 needs to echo data back to zenity as it processes some data, but zenity never hears the echos. It seems the echos are lost because cmd2 is delimited by the (..). An outline of my code is shown below. cases 1 and 3 work fine. Zenity never receives the echo from case 2. I've verified that case 2 does properly echo by also sending the data to a file. I'm looking for a method to echo the data to zenity while reading.

function() {
while [ "$nf" -lt "$num_of_files" ]; do
    ((nf=$nf+1))
    case "$process" in
        1)
        while read -d$'\r' str1; do
            (commands ... ) 
            echo "$percent_update"
        done
        ;;
        2) #feed the standout of cmd0 to cmd1 and the standerr of cmd0 to cmd2 
        command0 > >(command1) 2> >(command 2 ....
        while read -d$'%' str1; do
            percent=$(echo "$str1" | sed 's/\x08//g' | sed 's/ //g')
            percent=$(scaler "$percent" "$nf" "$num_of_files")
            echo "$percent_update"
            echo "$percent_update" >>just to verify data exists & is good.txt
        done)
        ;;
        3)
            (more commands)
            echo percent        
        ;;
    esac
done | zenity --progress --percentage=0 --auto-close
}
  • What is the while reading from? You are sending both stderr and stdout to the two commands, the while will read the output of both. Is that what you want? – terdon Oct 17 '15 at 13:53
  • the while-do-done is really command 2 ... it is reading the standard error output from command 0 and processing it for zenity. I confirmed that the data is correct and available by echo to a text file. Its just that the echo command is not seen by zenity. – daniel Oct 17 '15 at 15:40
  • Hang on, so you want to send stdout of command0 to command1 and loop over the stderr of command0 with a while loop? Why don't you just do command0 2>&1 > >(command1 2>/dev/null) | while read ... then? The >/dev/null is needed because without it, your while loop will get both the stderr of command0 and the stdout of command1. – terdon Oct 17 '15 at 15:55
2

Your problem is that you are redirecting stderr before redirecting stdout. It should work if you switch them around. To illustrate, consider the following scripts. foo.sh prints to stderr and stdout:

#!/usr/bin/env bash
## foo.sh

## Print "out" to standard output
echo out
## Print "error" to standard error
echo error >&2

bar.sh reads input:

#!/usr/bin/env bash
## bar.sh

read input
## Print your input
echo "bar.sh read: $input"

And so does baz.sh:

#!/usr/bin/env bash
## baz.sh

read input
## Print your input
echo "baz.sh read: $input"

Now, if I run these three as you seem to be attempting to do and pass their output to a while loop, it works as expected:

$ foo.sh 2> >(bar.sh) > >(baz.sh) | while read line; do echo "$line"; done
bar.sh read: error
baz.sh read: out

However, it fails if you do it the other way around:

$ foo.sh > >(bar.sh) 2> >(baz.sh) | while read line; do echo "$line"; done
bar.sh read: out
  • terndon, After thinking about it for a while, your suggestion is obvious (except to me initially) ... I tried it out and it works fine ... thanks. – daniel Oct 17 '15 at 15:04
  • Just to clarify the original situation: The first command does some file processing that outputs one flow to standard output that must be processed by another command. The first command also outputs process status via the standard error that I was processing and sending to zenity. By switching as Terndon suggested, I was able to get the process status data sent to zenity. However, the question now is, is the standard output data polluted in some way by this switch? – daniel Oct 17 '15 at 15:17
  • @daniel it may well be. I'm afraid I'm not 100% clear on the details of why this works, only that it seems to. That might be worth a question of its own. – terdon Oct 17 '15 at 15:38
  • I'm having trouble to know what question to ask now ... except to repost the question with some additional questions ... By swapping as you suggested, it seems to work ... but I don't have an easy way to know if the data is being polluted in the next step. – daniel Oct 17 '15 at 15:50
0

That is a very silly redirection chain you've strung together there. I don't understand what you're really trying to do there, but you have definitely misinterpreted the source of your problem. Maybe this will give you an idea:

[mikeserv@desktop top]$ > >(sed 's/^/hey there:\t/') 2> >(ls -l /dev/fd/*)

ls: cannot access /dev/fd/10: No such file or directory
ls: cannot access /dev/fd/255: No such file or directory
ls: cannot access /dev/fd/3: No such file or directory
hey there:  lr-x------ 1 mikeserv mikeserv 64 Oct 17 06:38 /dev/fd/0 -> pipe:[10484689]
hey there:  l-wx------ 1 mikeserv mikeserv 64 Oct 17 06:38 /dev/fd/1 -> pipe:[10484688]
hey there:  lrwx------ 1 mikeserv mikeserv 64 Oct 17 06:38 /dev/fd/2 -> /dev/pts/3
hey there:  l-wx------ 1 mikeserv mikeserv 64 Oct 17 06:38 /dev/fd/63 -> pipe:[10484688]

Of course echo doesn't write out to the while loop's stdout - you replace it in that command with whatever pipe command1 reads when you do:

> >(command1) 2> >(command2)

Redirections are processed in order - from left to right for each command. And each of those process substitutions you do all affect the same command.

I'm willing to bet what you're actually trying to do is a lot closer to:

command0 | command1 2>&1 >/dev/null | command2
  • Why "silly"? I see no reason why it shouldn't work. – terdon Oct 17 '15 at 13:58
  • @terdon - it's backwards. how do you think the sed above manages to read and modify the output of the ls command? – mikeserv Oct 17 '15 at 13:59
  • cmd0 2> >(cmd1) > >(cmd2) will work as expected. Try 2> >(sed 's/^/hey there:\t/') > >(ls -l /dev/fd/*) instead. Can't say I'm clear on exactly what is going on though. Apparently, redirecting stderr first fails. – terdon Oct 17 '15 at 14:06
  • @terdon - no it wont. at least, it wont unless you expect all of cmd2's stderr to be directed into cmd1's stdin. you just swapped streams, but you didnt solve the problem. and if cmd0 writes anything to stdout cmd2 gets that, too. its all interleaved. – mikeserv Oct 17 '15 at 14:09
  • I certainly seem to have. Have a look at the example scripts in my answer. – terdon Oct 17 '15 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.