Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preserving whitespaces in a string as a command line argument

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 ---------#
like image 345
crozzfire Avatar asked Oct 12 '09 11:10

crozzfire


3 Answers

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

like image 172
Gordon Davisson Avatar answered Nov 15 '22 10:11

Gordon Davisson


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.

like image 27
Dennis Williamson Avatar answered Nov 15 '22 09:11

Dennis Williamson


I have a suggestion:

# iterate through the passed arguments, save them to new properly quoted ARGS string
while [ -n "$1" ]; do
   ARGS="$ARGS '$1'"
   shift
done

# invoke the command with properly quoted arguments
my_command $ARGS
like image 25
Pavel Avatar answered Nov 15 '22 08:11

Pavel