Reputation: 21413
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?
Upvotes: 241
Views: 358577
Reputation: 2490
A more dynamic way would be:
function myFunction {
for i in "$*"; do echo "$i"; done;
}
Upvotes: 16
Reputation: 1
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...
Upvotes: -2
Reputation: 343181
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.
Upvotes: 224
Reputation: 235
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"
Upvotes: 10
Reputation: 362
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).
Upvotes: 4
Reputation: 359
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
Upvotes: 35
Reputation: 497
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
Upvotes: 0
Reputation: 76611
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.
Upvotes: 8