
Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 18, 2024
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.
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.
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.
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.
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.
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.
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.
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.
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.
Another approach for transforming the output of a brace expansion into a comma-separated string is based on three steps:
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.
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.
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.
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.