1

I have a shell called "name_value.sh" that I want to pass parameters generated in a sub-shell. How can I ensure the command receiving parameters from the sub shell retain spaces?

NOTE: This is an extremely simplified example of what I am doing. Please read completely before responding.

A simplified example is:

./name_value.sh $(echo "no_spaces"; echo "with spaces")

Where name_value.sh looks like this:

#!/bin/bash
echo "Name=$1"
echo "Value=$2"

Desired output is:

Name=no_spaces
Value=with spaces

This is a greatly simplified example. My real sub shell is complex, loops and outputs dozens of name/value pair that must all be generated at the same time and passed to name_value.sh at the same time. I also have no control over the shell file I am calling.

I have tried echoing with quotes and using printf with "%q". I also considered putting the results of the subshell in an array first but can't get that to work either. I need the parent shell to interpret the sub shell as if the text were entered in place of the sub shell.

  • This will work as expected: ./namevalue.sh "$(echo "no_spaces")" "$(echo "with spaces")" – George Vasiliou Jul 1 '17 at 21:16
  • Why "using a subshell"? the obvious way is to use an array: arr=("no_spaces" "with spaces") ; ./name_value.sh "${arr[@]}" – steeldriver Jul 1 '17 at 21:29
  • @George, I said the subshell is much more complex. e.g. It loops through arrays and files to generate the name/value pair. So simply echoing in two different sub shells is not a solution. – Tim Jul 2 '17 at 17:49
  • @steeldriver, I wanted to avoid creating additional arrays. Using a subshell injects the logic where I want it instead of separating it. This makes sense when you see this in the context of the full script I am creating. – Tim Jul 2 '17 at 17:51
  • @steeldriver... I am starting to reconsider inlining the code. Though in my case it will lead to more clarity the complexity required to make bash work with the sub shell may result in less maintainable code. – Tim Jul 2 '17 at 18:19
4

Yes. Set the IFS variable (which usually contains space,tab,newline) to be just a newline. That way, spaces and tabs will not be used for word splitting. This will give you your desired output.

IFS=$'\n'
set -o noglob # disable the second effect of leaving that
              # $(...) unquoted.
./name_value.sh $(echo "no_spaces"; echo "with spaces")

However, what I would do is have the script read from stdin.

# name_value.sh
IFS= read -r name
IFS= read -r value
echo "Name=$name"
echo "Value=$value"

then

( echo no_spaces; echo with spaces ) | ./name_value.sh

I think this approach is more robust.

  • Unfortunately I can't control the script I am calling. It is a third party script. What I gave is just an example to simplify the concept. My understanding is that changing IFS and noglob will affect the other script I am calling. Is that incorrect? I am starting to think that inlining the code may be a bad idea in spite of the clarity it would provide my code. – Tim Jul 2 '17 at 18:13
  • 1
    @Tim Changing IFS and noglob in the parent script does not affect the execution of the other script. – Gilles 'SO- stop being evil' Jul 2 '17 at 21:26
1

When you use this command

./name_value.sh $(echo "no_spaces"; echo "with spaces")

The bash execute the "sub-shells" commands in "$()" and return the output string

Example

Input command: ./name_value.sh $(echo "no_spaces"; echo "with spaces")

Processed command: ./name_value.sh no_spaces with spaces

The next step is execute you bash script with three arguments

First argument: no_space

Second argument: with

Third argument: spaces


This is the same as calling the script manually with the command

./name_value.sh no_spaces with spaces

For solve you problem, you need to insert the quotes around the sub-shell call "$()"

You need this

./name_value.sh $(echo "no_spaces") "$(echo "with spaces")"

And you processed command is

./name_value.sh no_spaces "with spaces"

And finally, you output it will be

Name=no_spaces
Value=with spaces
  • It is the same effect in this very case and with the default value of $IFS, but not in the general case. What happens upon unquoted expansions is (thankfully) very different from the shell parsing of the same strings once expanded (for instance echo $(echo ";reboot") is not the same as echo; reboot). It's missleading to imply that. – Stéphane Chazelas Jul 2 '17 at 18:05
  • Good point @Stéphane Chazelas. I want the output to be interpreted as if I typed it. That is "with spaces". But if Bash interpreted the output literally then "; reboot" would actually reboot the machine. – Tim Jul 2 '17 at 18:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.