bloody
bloody

Reputation: 1168

Group command with a pipeline in Bash

In the book "The Linux Command Line" the author presents an example of sorting an array:

arr=(f e d c b a)
arr_sorted=($(for i in "${arr[@]}"; do echo $i; done | sort))

The output from the for loop (which prints all subsequent array values with echo) is pipelined to sort.

On the other hand, in another chapter the author presents a similar example but exploiting a Bash "group command" which is denoted by surrounding braces { } (I minimized his script preserving the idea):

declare -A arr  # an associative array
arr["key0"]=val0
arr["key2"]=val2
arr["key1"]=val1
{ for i in "${!arr[@]}"; do
    printf "%s: %s\n" "$i" "${arr["$i"]}"
done } | sort

The author's point is: "(...) Also note that the entire loop is enclosed in braces thus forming a group command. This permits the entire output of the loop to be piped into the sort command."

However I ran this script (both the book's original and the minimized) both with and without "group command" braces and they all worked perfectly the same - the output is equivalent.

So why the author insists on using a group command in the above case although it works perfectly OK without it and even he himself showed a similar working version (with arr_sorted) in the previous chapter? Maybe I'm missing something else here.

Upvotes: 0

Views: 637

Answers (2)

chepner
chepner

Reputation: 532238

The command group would be useful if you wanted to combine the output of two or more separate commands. For example,

{
   for i in "${!arr[@]}"; do
       printf "%s: %s\n" "$i" "${arr["$i"]}"
   done

   while IFS=, read -r a b; do
       printf "%s: %s\n" "$a" "$b"
   done < some_file.txt
} | sort

But as you noticed, a for loop is already a single command, so there's no point in wrapping it inside another compound command to collect its output for a pipe.


A command group is especially nice for avoiding repeated redirections, which requires repeated opening and closing of files. Code like

echo ... > some_file.txt
echo ... >> some_file.txt
echo ... >> some_file.txt
echo ... >> some_file.txt
echo ... >> some_file.txt

can be replaced with

{
  echo ...
  echo ...
  echo ...
  echo ...
  echo ...
} > some_file.txt

which opens some_file.txt once, not five times.

Upvotes: 1

KamilCuk
KamilCuk

Reputation: 141768

There is no difference between putting a single command in { } braces or not.

The:

{ for i in "${!arr[@]}"; do
    printf "%s: %s\n" "$i" "${arr["$i"]}"
done } | sort

is equivalent to:

for i in "${!arr[@]}"; do
    printf "%s: %s\n" "$i" "${arr["$i"]}"
done | sort

Ex.:

{ { { { { echo a; }; }; }; }; }

is just echo a

Upvotes: 1

Related Questions