1. Overview
In shell scripting, brace expansion is a powerful feature that allows us to generate multiple strings by specifying patterns within curly braces. The resulting strings are normally separated by a space character. One common task is transforming the output of a brace expansion into a comma-separated string.
In this tutorial, we’ll explore different methods to produce strings with comma separators by using brace expansion.
2. Sample Task
Let’s suppose we have the following brace expansion:
$ echo file{A,B,C,D}
fileA fileB fileC fileD
The output shows four words separated by space characters. To reiterate, we’d like to change the delimiter from a space character to a comma so that the output is a comma-separated string.
Let’s explore various ways to achieve this task.
3. Using echo and tr
We can pass the brace expansion directly to echo and pipe the output to tr, which enables us to translate spaces into commas:
$ echo file{A,B,C,D} | tr ' ' ','
fileA,fileB,fileC,fileD
The result is a comma-separated string with the contents of the original expansion.
4. Using echo and awk
We can also pipe the output of the brace expansion to awk with its gsub() function:
echo file{A,B,C,D} | awk '{gsub(/ /, ","); print}'
awk‘s gsub() function performs global substitution, allowing us to replace space characters with commas with regular expressions.
5. Using echo and sed
Alternatively, we can use sed to substitute each space character with a comma:
$ echo file{A,B,C,D} | sed 's/ /,/g'
fileA,fileB,fileC,fileD
In this case, we pipe the output of the brace expansion to sed, which replaces spaces with commas globally.
6. Using printf and sed
We can also use printf in combination with sed to achieve the desired result:
$ printf "%s," file{A,B,C,D} | sed 's/,$/\n/'
fileA,fileB,fileC,fileD
The printf command used with the %s string format, followed by a comma, removes the spaces and appends a comma to each element of the brace expansion. We then pipe the output to sed, which replaces the trailing comma with a newline character.
7. Using echo and Parameter Expansion
Another approach is to convert space characters to commas using one of Bash‘s built-in parameter expansion features:
$ ( x=$(echo file{A,B,C,D}); echo ${x// /,} )
fileA,fileB,fileC,fileD
Here, we use command substitution to save the output of the brace expansion into a variable named x. Then, we use the parameter expansion feature of Bash which allows us to globally replace every space character with a comma in the x variable.
It’s important to note that the entire expression is enclosed within parentheses, creating a subshell, to prevent the x variable from persisting in the current shell environment.
8. Using Arrays and IFS
Another approach is to save the output of the brace expansion into an array. Then, we set the Internal Field Separator (IFS) to a comma and echo the array elements:
$ ( array=( file{A,B,C,D} ); IFS=','; echo "${array[*]}" )
fileA,fileB,fileC,fileD
It’s important in this case to use ${array[*]} instead of ${array[@]} so that IFS can act as the delimiter. Also here, we’ve wrapped the commands within a subshell so as not to retain the array or the custom IFS variable.
9. Using set and IFS
Similarly, we can use the set command to arrange the elements of the brace expansion as command line arguments. Then, we configure the IFS variable to a comma and echo out the positional arguments denoted by $*:
$ ( set -- file{A,B,C,D}; IFS=','; echo "$*" )
fileA,fileB,fileC,fileD
Here again, we run the entire commands within a subshell so as not to alter the current shell’s IFS variable.
10. Using Arrays, printf, and paste
Another approach for transforming the output of a brace expansion into a comma-separated string is based on three steps:
- store the output of the brace expansion in an array
- use printf to print out the array elements, each on a separate line
- use paste to serialize the lines into a single line delimited by commas
Applying the above procedure, we obtain the desired result:
$ array=( file{A,B,C,D} )
$ printf "%s\n" "${array[@]}" | paste -s -d ','
fileA,fileB,fileC,fileD
The -s option used with the paste command allows us to merge multiple lines into a single line, while the -d option specifies the delimiter to use when merging the lines.
11. Using a for Loop and sed
An alternative approach, though possibly less efficient, involves using a for loop to echo each element of the brace expansion on a single line. Additionally, a comma is appended to each element, and the -n flag is used with echo to eliminate the trailing newline character. The output is then piped into sed to remove the last comma in the string. Finally, we save the result in a variable named x and then echo its content:
$ ( x=$(for i in file{A,B,C,D}; do echo -n "$i",; done | sed 's/,$//') ; echo "$x" )
fileA,fileB,fileC,fileD
When we echo the x variable at the end, the expansion includes a trailing newline character, and we obtain the required result.
It’s worth noting that we’ve also wrapped the entire expression within a subshell since we’re not interested in saving the x variable in the current shell environment.
12. Using a for Loop and Parameter Expansion
Another method that uses a for loop involves iterating over the elements of the brace expansion and adding a comma before each element except for the first one:
$ str=''
$ for i in file{A,B,C,D}; do str="${str:+$str,}$i"; done
$ echo "$str"
fileA,fileB,fileC,fileD
The str string is initialized to the empty string. Therefore, during the first iteration, str gets overwritten by the first element of the brace expansion. This occurs because “${str:+$str,}” expands to str when str is the empty string. Thereafter, in each iteration, a comma is appended to the previous str string followed by a new element from the brace expansion.
13. Conclusion
In this article, we’ve explored several methods to transform a brace expansion into a comma-separated string. Each approach involved using some combination of commands such as echo, tr, awk, printf, sed, and paste, or the use of arrays, the IFS variable, for loops, and parameter expansion features to accomplish the task.