3

I've got a program that I want to call by passing parameters from a shell variable. Throughout this question, I am going to assume that it is given by

#!/bin/sh
echo $#

i.e. that it prints out the number of arguments that are passed to it. Let's call it count-args.

I call my program like this:

X="arg1 arg2"
count-args $X

This works quite well. But now one of my arguments has a whitespace in it and I can't find a way to escape it, e.g. the following things do not work:

X="Hello\ World"
X="Hello\\ World"
X="'Hello World'"

In all of the cases, my program count-args prints out 2. I want to find a way so I can pass the string Hello World and that it returns 1 instead. How?

Just for clarification: I do not want to pass all parameters as a single string, e.g.

X="Hello World"
count-args $X

should print out 2. I want a way to pass parameters that contain whitespaces.

Markus Mayr
  • 4,038
  • 1
  • 20
  • 42
  • You're contradicting yourself. ```X="Hello World"; count-args $X``` should print out ```1```. And to achieve this use quotes as show by user1934428: ```"$X"```. If you wish this to interpret this single string as multiple params, you're doing it wrong: http://mywiki.wooledge.org/BashFAQ/050 ! – dekkard Mar 21 '16 at 11:09
  • @dekkard: As I have found a way to do exactly what I want, I am quite confident that my requirements are consistent. But thanks for that link, it is very helpful. – Markus Mayr Mar 21 '16 at 11:51

4 Answers4

3

This can be solved with xargs. By replacing

count-args $X

with

echo $X | xargs count-args

I can use backslashes to escape whitespaces in $X, e.g.

X="Hello\\ World"
echo $X | xargs count-args

prints out 1 and

X="Hello World"
echo $X | xargs count-args

prints out 2.

Markus Mayr
  • 4,038
  • 1
  • 20
  • 42
3

Use an array to store multiple, space-containing arguments.

$ args=("first one" "second one")
$ count-args "${args[@]}"
2
chepner
  • 497,756
  • 71
  • 530
  • 681
2
 count-args "$X"

The quotes ensure in bash, that the whole content of variable X is passed as a single parameter.

user1934428
  • 19,864
  • 7
  • 42
  • 87
  • Worth noting that this doesn't require any special handling of the *value* of `X`: `X="Hello World"` sets `X` to a string containing whitespace, and `count-args "$X"` calls the function with one argument. You also need to quote the expansion of `$1` inside the function to preserve the whitespace. – chepner Mar 21 '16 at 10:58
  • I think that this is not what I want. I do not want to pass all parameters as a single string. I want a way to pass parameters that contain whitespaces. Added a paragraph to my question. I hope that it is clearer now. – Markus Mayr Mar 21 '16 at 11:01
1

Your Counting script:

$ cat ./params.sh
#!/bin/sh
echo $#

For completeness here is what happens with various arguments:

$ ./params.sh
0
$ ./params.sh  1 2
2
$ ./params.sh
0
$ ./params.sh 1
1
$ ./params.sh 1 2
2
$ ./params.sh "1 2"
1

And here is what you get with variables:

$ XYZ="1 2" sh -c './params.sh $XYZ'
2
$ XYZ="1 2" sh -c './params.sh "$XYZ"'
1

Taking this a bit further:

$ cat params-printer.sh
#!/bin/sh
echo "Count: $#"
echo "1 : '$1'"
echo "2 : '$2'"

We get:

$ XYZ="1 2" sh -c './params-printer.sh "$XYZ"'
Count: 1
1 : '1 2'
2 : ''

This looks like what you wanted to do.

Now: If you have a script you cannot control and neither can you control the way the script is invoked. Then there is very little you can do to prevent a variable with spaces turning into multiple arguments.

There are quite a few questions around this on StackOverflow which indicate that you need the ability to control how the command is invoked else there is little you can do.

Passing arguments with spaces between (bash) script

Passing a string with spaces as a function argument in bash

Passing arguments to a command in Bash script with spaces

And wow! this has been asked so many times before:

How to pass argument with spaces to a shell script function

Community
  • 1
  • 1
chkdsk
  • 1,187
  • 6
  • 20