Joining bash arguments into single string with spaces

I believe that this does what you want. It will put all the arguments in one string, separated by spaces, with single quotes around all:

str="'$*'"

$* produces all the scripts arguments separated by the first character of $IFS which, by default, is a space.

Inside a double quoted string, there is no need to escape single-quotes.

Example

Let us put the above in a script file:

$ cat script.sh 
#!/bin/sh
str="'$*'"
echo "$str"

Now, run the script with sample arguments:

$ sh script.sh one two three four 5
'one two three four 5'

This script is POSIX. It will work with bash but it does not require bash.

A variation: concatenating with slashes instead of spaces

We can change from spaces to another character by adjusting IFS:

$ cat script.sh 
#!/bin/sh
old="$IFS"
IFS='/'
str="'$*'"
echo "$str"
IFS=$old

For example:

$ sh script.sh one two three four       
'one/two/three/four'

It's easier than you think:

#!/bin/bash
array="${@}"

echo $array

chmod +x that, and run it:

$ ./example.sh --foo bar -b az 
--foo bar -b az

update Tl;dr, use

"'${array[*]}'"

To be clear, I don't intend to replicate this answer. I just found there are minor differences to use @ and * to dereference all values from an array.

Under the hood, $* and $@ are all arrays, referring to the argv list.

From the question,

I'm trying to join all of the arguments to a Bash function into one single string with spaces separating each argument.

It has 2 sub-questions:

  1. concatenate the array input arguments into a string.
  2. pass the concatenated string as a single argument for the shell function.

First, concat array into a string,

array=("$@")
str="'${array[@]}'"
# or
str="'${array[*]}'"
# or
str=\'"${array[*]}"\'

Second, when you pass str to a function, let's count the number of arguments that function received,

#!/usr/bin/env bash

arr=(a b c d)

function count_args() {
  echo '$#' $#
}

count_args "'${arr[@]}'"
count_args \'"${arr[@]}"\'
count_args "'${arr[*]}'"
count_args \'"${arr[*]}"\'

output is

$# 4
$# 4
$# 1
$# 1

only arr[*] wraps the array into 1 argument for the shell function, why?

Cite from How to use arrays in bash script, which I found it's useful for me,

echo ${array[*]}
echo ${array[@]}

Both syntax let us access all the values of the array and produce the same results, unless the expansion it's quoted. In this case a difference arises: in the first case, when using @, the expansion will result in a word for each element of the array.

Whereas using * will group the entire array into one single argument during expansion.