7

Notice that we return from a loop, which is redirected.

I don't know, if I should worry about the write buffer of "file".

function f {
    i=1
    while :
    do
        echo aaaaaaaaaaaaabbbbbbbbbbbbbbbbb
        ((i++))
        if [ $i -gt 3 ]
        then
            return    # return while redirected
        fi
    done >> file    # writing to file
}

f

NOTE: I am aware that this function could be easily rewritten, so that is would not return from within the redirected loop. However this is just a simplified example for the purpose of this question.

So please, do not try to improve this code.

I am not interested in workarounds, either.

My sole question is, if there is something I should be particularly aware of. Like the file descriptor is not closed properly. Or sometimes I can expect only half of the buffer (i.e. "aaaaaa") to be written into the file.

I would like to know, if this is a very bad idea, and why? Or maybe it would work without unforeseen race conditions or similar? (but again, I don't want answers like "it is bad because you should use this-and-this pattern instead")

11

While each command may have its own write buffer, there is no write buffer that is shared between commands even built-in in bash (or even two invocations of a same command, built-in or not).

Even ksh93 which has been known to do some I/O optimisation (for instance, it will read-ahead and share some data on input (causing some bugs)), doesn't do it.

So, it will be safe in that regard. After a command finishes, like your echo aaaaaaaaaaaaabbbbbbbbbbbbbbbbb, and provided it doesn't fork unattended process running in background, you can be guaranteed that all I/O has been done.

A few notes though. In a function like:

f() {
  {
    echo x
    return
    echo y
  } > file
  echo something else
}

In the Bourne shell (and the Bourne shell only), that return would break output of the inner command group, but not return from the function as in that ancient shell, that command group would run in a subshell because of the redirection (so you'd see the something else).

That no longer happens in modern shells like bash, but you'd have the same problem in bash if you wrote:

f() {
  (
    echo x
    return
    echo y
  ) > file
  echo something else
}

or

f() {
  {
    echo x
    return
    echo y
  } | tr xy ab
  echo something else
}

Beware there are cases where some commands are not waited for. In:

f() {
  {
    echo >(sleep 1; echo x)
    return
  } > file
}
f; cat file

You may find that x doesn't show up because cat is run before echo x.

Some shells (though not bash) have similar potential issues with pipeline components other that the rightmost one.

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.