244

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?

5
  • 1
    Works for me... I use full syntax for functions though "function bla() { echo $1; }", can't make short one into a one liner. Not sure it makes a difference. What version of bash? Commented Dec 30, 2009 at 23:28
  • 16
    try echo "$@" or for i in "$@"; do echo $i ; done for using correctly quoted parameters containing spaces. This is the very clearly mentioned in all bash documentation under positional parameters section. Commented Jun 14, 2013 at 7:06
  • 2
    I was having a similar problem, trying to pass one quoted string as a parameter and only the first word of the string being recognized as part of the parameter. Samveen's suggestion to change $1 to $@ worked for me. Note that I was only passing one parameter to the function, but if I'd been passing more using the for statement would have been necessary. Commented Apr 20, 2014 at 8:01
  • 1
    See also stackoverflow.com/questions/10067266/… Commented Feb 8, 2017 at 4:31
  • 3
    try myFunction "$@" Commented Sep 22, 2017 at 6:03

8 Answers 8

225

You should add quotes and also, your function declaration is wrong.

myFunction()
{
    echo "$1"
    echo "$2"
    echo "$3"
}

And like the others, it works for me as well.

Sign up to request clarification or add additional context in comments.

3 Comments

This works very well for me also. If we are calling another function inside myFunction then pass arguments with quotes. Cheers :)
Can you explain why one needs quotes? I tried both with and without, and it did not work for me. I'm using Ubuntu 14.04, GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu). What does work for me is using $@ (with or without quotes).
@KyleBaker, without the quotes, $@ behaves just like unquoted $* -- results are string-split and then individually glob-expanded, so if you have tabs they'll be converted to spaces, if you have words that can be evaluated as glob expressions they will be, etc.
35

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

Comments

16

A more dynamic way would be:

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

4 Comments

Ah great! this is exactly what I was looked for for some time on many questions. Thank you!
What do you mean by "more dynamic"? Can you elaborate? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).
As a supplement, here is the reference for syntax $* : gnu.org/software/bash/manual/bash.html#Special-Parameters, "($*) Expands to the positional parameters, starting..."
In my copy of bash this produces all the arguments on a single line. Did you intend to use "$@" ?
10

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"

Comments

8

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.

2 Comments

The syntax highlighting is kind of funky. What does that indicate, if anything?
@PeterMortensen - the syntax highlighting is implemented by the site and doesn't indicate anything.
4

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).

Comments

0

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

1 Comment

OP used myFunction "firstString" "second string with spaces" "thirdString" and it didn't work for him. So what you propose does not apply to this question.
-2

I 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...

1 Comment

The correct answer is "$@", not all quoted "$1", "$2", ... positional paramters nor $*.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.