[bash] Passing a string with spaces as a function argument in bash

I'm writing a bash script where I need to pass a string containing spaces to a function in my bash script.

For example:

#!/bin/bash

myFunction
{
    echo $1
    echo $2
    echo $3
}

myFunction "firstString" "second string with spaces" "thirdString"

When run, the output I'd expect is:

firstString
second string with spaces
thirdString

However, what's actually output is:

firstString
second
string

Is there a way to pass a string with spaces as a single argument to a function in bash?

This question is related to bash function

The answer is


Had the same kind of problem and in fact the problem was not the function nor the function call, but what I passed as arguments to the function.

The function was called from the body of the script - the 'main' - so I passed "st1 a b" "st2 c d" "st3 e f" from the command line and passed it over to the function using myFunction $*

The $* causes the problem as it expands into a set of characters which will be interpreted in the call to the function using whitespace as a delimiter.

The solution was to change the call to the function in explicit argument handling from the 'main' towards the function : the call would then be myFunction "$1" "$2" "$3" which will preserve the whitespace inside strings as the quotes will delimit the arguments ... So if a parameter can contain spaces, it should be handled explicitly throughout all calls of functions.

As this may be the reason for long searches to problems, it may be wise never to use $* to pass arguments ...

Hope this helps someone, someday, somewhere ... Jan.


Simple solution that worked for me -- quoted $@

Test(){
   set -x
   grep "$@" /etc/hosts
   set +x
}
Test -i "3 rb"
+ grep -i '3 rb' /etc/hosts

I could verify the actual grep command (thanks to set -x).


Your definition of myFunction is wrong. It should be:

myFunction()
{
    # same as before
}

or:

function myFunction
{
    # same as before
}

Anyway, it looks fine and works fine for me on Bash 3.2.48.


Another solution to the issue above is to set each string to a variable, call the function with variables denoted by a literal dollar sign \$. Then in the function use eval to read the variable and output as expected.

#!/usr/bin/ksh

myFunction()
{
  eval string1="$1"
  eval string2="$2"
  eval string3="$3"

  echo "string1 = ${string1}"
  echo "string2 = ${string2}"
  echo "string3 = ${string3}"
}

var1="firstString"
var2="second string with spaces"
var3="thirdString"

myFunction "\${var1}" "\${var2}" "\${var3}"

exit 0

Output is then:

    string1 = firstString
    string2 = second string with spaces
    string3 = thirdString

In trying to solve a similar problem to this, I was running into the issue of UNIX thinking my variables were space delimeted. I was trying to pass a pipe delimited string to a function using awk to set a series of variables later used to create a report. I initially tried the solution posted by ghostdog74 but could not get it to work as not all of my parameters were being passed in quotes. After adding double-quotes to each parameter it then began to function as expected.

Below is the before state of my code and fully functioning after state.

Before - Non Functioning Code

#!/usr/bin/ksh

#*******************************************************************************
# Setup Function To Extract Each Field For The Error Report
#*******************************************************************************
getField(){
  detailedString="$1"
  fieldNumber=$2

  # Retrieves Column ${fieldNumber} From The Pipe Delimited ${detailedString} 
  #   And Strips Leading And Trailing Spaces
  echo ${detailedString} | awk -F '|' -v VAR=${fieldNumber} '{ print $VAR }' | sed 's/^[ \t]*//;s/[ \t]*$//'
}

while read LINE
do
  var1="$LINE"

  # Below Does Not Work Since There Are Not Quotes Around The 3
  iputId=$(getField "${var1}" 3)
done<${someFile}

exit 0

After - Functioning Code

#!/usr/bin/ksh

#*******************************************************************************
# Setup Function To Extract Each Field For The Report
#*******************************************************************************
getField(){
  detailedString="$1"
  fieldNumber=$2

  # Retrieves Column ${fieldNumber} From The Pipe Delimited ${detailedString} 
  #   And Strips Leading And Trailing Spaces
  echo ${detailedString} | awk -F '|' -v VAR=${fieldNumber} '{ print $VAR }' | sed 's/^[ \t]*//;s/[ \t]*$//'
}

while read LINE
do
  var1="$LINE"

  # Below Now Works As There Are Quotes Around The 3
  iputId=$(getField "${var1}" "3")
done<${someFile}

exit 0

I'm 9 years late but a more dynamic way would be

function myFunction {
   for i in "$*"; do echo "$i"; done;
}

The simplest solution to this problem is that you just need to use \" for space separated arguments when running a shell script:

#!/bin/bash
myFunction() {
  echo $1
  echo $2
  echo $3
}
myFunction "firstString" "\"Hello World\"" "thirdString"

You could have an extension of this problem in case of your initial text was set into a string type variable, for example:

function status(){    
  if [ $1 != "stopped" ]; then
     artist="ABC";
     track="CDE";
     album="DEF";
     status_message="The current track is $track at $album by $artist";
     echo $status_message;
     read_status $1 "$status_message";
  fi
}

function read_status(){
  if [ $1 != "playing" ]; then
    echo $2
  fi
}

In this case if you don't pass the status_message variable forward as string (surrounded by "") it will be split in a mount of different arguments.

"$variable": The current track is CDE at DEF by ABC

$variable: The