views:

437

answers:

4

I'm facing a small problem here, I want to pass a string containing whitespaces , to another program such that the whole string is treated as a command line argument.

In short I want to execute a command of the following structure through a bash shell script: command_name -a arg1 -b arg2 -c "arg with whitespaces here"

But no matter how I try, the whitespaces are not preserved in the string, and is tokenized by default. A solution please,

edit: This is the main part of my script:

#!/bin/bash

#-------- BLACKRAY CONFIG ---------------#
# Make sure the current user is in the sudoers list
# Running all instances with sudo

BLACKRAY_BIN_PATH='/opt/blackray/bin' 
BLACKRAY_LOADER_DEF_PATH='/home/crozzfire'
BLACKRAY_LOADER_DEF_NAME='load.xml'
BLACKRAY_CSV_PATH='/home/crozzfire'
BLACKRAY_END_POINT='default -p 8890'
OUT_FILE='/tmp/out.log'

echo "The current binary path is $BLACKRAY_BIN_PATH"


# Starting the blackray 0.9.0 server
sudo "$BLACKRAY_BIN_PATH/blackray_start"

# Starting the blackray loader utility
BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "\"$BLACKRAY_END_POINT\"""

sudo time $BLACKRAY_INDEX_CMD -a $OUT_FILE

#--------- END BLACKRAY CONFIG ---------#
+1  A: 

Backslashes "\ "?

Kinopiko
A: 

probably you need to surround the argument by double quotes (e.g. "${6}").

Following OP comment it should be "$BLACKRAY_END_POINT"

dimba
Tried. But it still takes just "default" and not the whole string :(
crozzfire
Replace -e \"$BLACKRAY_END_POINT\"" to "\"$BLACKRAY_END_POINT\"". You need "" to escape spaces in your script and additional \"\" to escape spaces when the command is executed
dimba
still no luck, it takes--> "default as the arg now (extra open quotes). for running I am using: sudo time $CMD -a $OUT_FILE . If I replace $CMD as "$CMD" , it gives me a no such file or directory error.
crozzfire
+1  A: 

Edit:

Try:

BLACKRAY_END_POINT="'default -p 8890'"

or

BLACKRAY_END_POINT='"default -p 8890"'

or

BLACKRAY_END_POINT="default\ -p\ 8890"

or

BLACKRAY_END_POINT='default\ -p\ 8890'

and

BLACKRAY_INDEX_CMD="$BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e $BLACKRAY_END_POINT"

Original answer:

Is blackray_loader a shell script?

Here is a demonstration that you have to deal with this issue both when specifying the parameter and when handling it:

A text file called "test.txt" (include the line numbers):

1 two words
2 two        words
3 two
4 words

A script called "spacetest":

#!/bin/bash
echo "No quotes in script"
echo $1
grep $1 test.txt
echo

echo "With quotes in script"
echo "$1"
grep "$1" test.txt
echo

Running it with ./spacetest "two--------words" (replace the hyphens with spaces):

No quotes in script
two words
grep: words: No such file or directory
test.txt:1 two words
test.txt:2 two        words
test.txt:3 two

With quotes in script
two        words
2 two        words

You can see that in the "No quotes" section it tried to do grep two words test.txt which interpreted "words" as a filename in addition to "test.txt". Also, the echo dropped the extra spaces.

When the parameter is quoted, as in the second section, grep saw it as one argument (including the extra spaces) and handled it correctly. And echo preserved the extra spaces.

I used the extra spaces, by the way, merely to aid in the demonstration.

Dennis Williamson
Agreed. But in my case, I'm not passing any args to my bash script, instead I'm hardcoding an argument(with spaces) which needs to be passed to a command. This command (blackray_loader) is called withing my bash script. I just need to preserve the argument's whitespaces and pass it as one whole string.
crozzfire
That's exactly what I'm demonstrating. In the script above, `grep` is a stand-in for your `blackray_loader`. Your command will need to properly handle the parameters. However see the edit for another thing to try.
Dennis Williamson
A: 

You're running into this problem because you store the command in a variable, then expand it later; unless there's a good reason to do this, don't:

sudo time $BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT" -a $OUT_FILE

If you really do need to store the command and use it later, there are several options; the bash-hackers.org wiki has a good page on the subject. It looks to me like the most useful one here is to put the command in an array rather than a simple variable:

BLACKRAY_INDEX_CMD=($BLACKRAY_BIN_PATH/blackray_loader -c $BLACKRAY_LOADER_DEF_PATH/$BLACKRAY_LOADER_DEF_NAME -d $BLACKRAY_CSV_PATH -e "$BLACKRAY_END_POINT")

sudo time "${BLACKRAY_INDEX_CMD[@]}" -a $OUT_FILE

This avoids the whole confusion between spaces-separating-words and spaces-within-words because words aren't separated by spaces -- they're in separate elements of the array. Expanding the array in double-quotes with the [@] suffix preserves that structure.

(BTW, another option would be to use escaped quotes rather like you're doing, then run the command with eval. Don't do this; it's a good way to introduce weird parsing bugs.)

Gordon Davisson