5

I am wanting to execute a command with arguments read in from a file. This works fine, until 1 of the arguments needs to have a space.

I have tried grouping the words with quotes and backslashes, but neither have worked.

The functionality I am after is exactly what xargs does, except I need to call a function rather than a command as it relies on other variables set up elsewhere in the script

script:

do_echo() {
    echo '$1:' $1
    echo '$2:' $2
}
line=`cat input.txt` #cat used for simplicity, can have more than 1 line
do_echo $line

input.txt:

"hello world" "hello back"

Expected result:

$1: hello world
$2: hello back

Observed result:

$1: "hello
$2: world"

EDIT:

I am using this to execute the same command multiple times with different inputs. There is up to 15 parameters per line, and could be upwards of 50 lines.

A tabular format would be ideal, although the current answer of putting each parameter on a line will work.

2
  • Does using do_echo "$line" provide different results than do_echo $line? Commented Aug 24, 2012 at 14:29
  • 1
    @twalberg yes, it prints the entire line as the first argument, $1 Commented Aug 24, 2012 at 14:34

2 Answers 2

4

Unquoted variables (as in do_echo $line) are strictly split at any character which is in the IFS variable (which is by default set to tab,space,newline). Strictly means really strictly, there is no way to quote or escape the splitting.

The basic workaround is to define an otherwise unneeded character (for example colon :) as splitting character.

for example

$ cat input.txt
hello world:hello back
$ line=$(head -n 1 input.txt)
$ OLDIFS=$IFS IFS=:
$ do_echo $line
$1: hello world
$2: hello back
$ IFS=$OLDIFS

Another workaround is using eval but eval is dangerous. You absolutely must trust the input!

$ cat input.txt
"hello world" "hello back"
$ line=$(head -n 1 input.txt)
$ eval do_echo "$line"
$1: hello world
$2: hello back
Sign up to request clarification or add additional context in comments.

1 Comment

thanks. the input is verified before executed, and eval is a nice quick solution
3

Instead of using quotes, separate each argument using a character that is guaranteed to not appear in an individual argument. For example, using a semi-colon:

hello world;hello back
argument 1;argument 2

Then you can read a set of arguments, one batch at a time, using read:

while IFS=';' read -a arguments; do
    do_echo "${arguments[@]}"
done < input.txt

An obscure ASCII control character, like the unit separator (ASCII 0x1f), would be less likely to appear in an argument if you can enter them in your file.

3 Comments

Thanks, I am actually using this to execute a command several times with different inputs. I guess I could separate groups of parameters with a blank line, but it would be nicer if i could have them all on a single line.
Can you use something besides a newline (comma, semicolon, etc) to separate arguments? It will be tricky to parse quoted arguments read from a file.
I can. The spaces are in file names provided read-only by a 3rd party :(, but I have control over everything else

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.