Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between {} 1>&2 and () 1>&2 in an output-captured function in bash

  1. with {} - execute while loop in the current shell

    function f {
        {
            while : ; do echo -n a; done  &
        } 1>&2
    }
    
    a=$( f ); echo "returned"
    

    -> f() will never return!!!

  2. () execute while loop in a subshell

    function f {
        (
            while : ; do echo -n a; done  &
        ) 1>&2
    }
    
    a=$( f ); echo "returned"
    

    -> f() will return!!!

Why? will one of them return, but not the other? I don't get it...


My analysis:

The while loop will be forked and start its own background process due to the ending & on the while-loop line. This background process inherits the current open fd list.

As far as I understand, since the while loop is encapsulated, it inherits the encapsulation's fd list. This is how

{ echo log; echo err 1>&2; } 1>l_file 2>e_file

works as expected, l_file will contain "log", e_file will contain "err".

So in either the case of {} 1>&2 or () 1>&2, bash is informed that it should expect no stdout to capture.

Why is it blocking on the {} 2>&1 case?

  • some evaluation order mystery?
  • maybe closing the stdout explicitly would help? I don't know the syntax, though, maybe {} 1>&- 1>&2 would help?

GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)


EDIT

Based on the answers so far, I did some more analysis:

11) {}

function f {
    {
        while : ; do echo -n a; done  &
        echo "after loop"
    } 1>&2
    echo "end of function"
}

a=$( f ); echo "returned"

-> after loop is displayed

12) ()

function f {
    (
        while : ; do echo -n a; done  &
        echo "after loop"
    ) 1>&2
    echo "end of function"
}

a=$( f ); echo "returned"

-> after loop is displayed

-> returned is displayed

like image 705
Zoltan K. Avatar asked Aug 17 '17 13:08

Zoltan K.


People also ask

What is the difference between () {} []?

() is a tuple: An immutable collection of values, usually (but not necessarily) of different types. [] is a list: A mutable collection of values, usually (but not necessarily) of the same type. {} is a dict: Use a dictionary for key value pairs.

Why {} === {} is false in JavaScript?

javascript compares objects by identity, not value. Each object, each {} is distinct.

What is the use of {} in JavaScript?

{} declares an object, with no members. Like an empty data container. [] would declare an empty array. Fun fact: Even arrays are objects in JavaScript.

What type is {} in JS?

JavaScript objects are written with curly braces {} . Object properties are written as name:value pairs, separated by commas.


1 Answers

A command substitution doesn't return until the FIFO it opens as output is closed.

When you redirect a subshell, that subshell doesn't hold a file descriptor pointing to the original FD; it doesn't have any need to, since the redirection will be implicitly ended by that subshell's termination.

When you redirect a block, the block needs to retain a copy of the original descriptor to restore on exit. Consequently, there will be an automatically-assigned file descriptor storing a copy of the original (pre-redirection) stdout, and the existence of this FD prevents the FIFO from having the write end closed.


Observe the difference:

f() {
  ls -l "/proc/$BASHPID/fd"
}

out1=$( ( f; ) 2>&1; )
out2=$( { f; } 2>&1; )

In the above, out1 may (with irrelevant fields stripped) look like:

0 -> /dev/pts/0
1 -> pipe:[1146313]
2 -> pipe:[1146313]
255 -> /dev/pts/0

...whereas out2 may under similar conditions look like:

0 -> /dev/pts/0
1 -> pipe:[1146327]
10 -> /dev/pts/0
2 -> pipe:[1146327]
255 -> /dev/pts/0

Note the additional FD 10, storing a backup to be restored.

like image 77
Charles Duffy Avatar answered Sep 23 '22 16:09

Charles Duffy