3

I would need to replace a string having spaces with another string in a file in a bash script where all calls should be done through a function that writes the command to a log file and then runs the command. The logrun function uses special character $@ for reading in the command. I'm trying to use sed for replacing but I can't find a way to escape spaces when the sed command having spaces in expression parameter goes through $@.

I have simplified the problem to test scripts where I use sed for replacing a c with a b c.

test1.sh works great:

#!/bin/bash

TESTFILE=/tmp/test.txt
echo "a c" > $TESTFILE
sed -i -e 's/a c/a b c/' $TESTFILE

test2.sh fails:

#!/bin/bash

function logrun() {
    CMD=$@
    $CMD
}

TESTFILE=/tmp/test.txt
echo "a c" > $TESTFILE
logrun sed -i -e 's/a c/a b c/' $TESTFILE

Result:

sed: -e expression #1, char 3: unterminated `s' command

The reason for error is the space(s) in the -e expression. I haven't found a way to call sed through that function. I have tried to use double quotes instead of single quotes and to escape spaces with a backslash etc. I am really curious to find out what's the correct way to do it.

talamaki
  • 5,324
  • 1
  • 27
  • 40
  • 3
    @Barmar You've closed several questions as a duplicate of http://stackoverflow.com/questions/13365553/setting-an-argument-with-bash. It would be good to find a more canonical duplicate. That question is a bit hard to parse through, particularly for someone asking about `$@`, which isn't mentioned at all in that post. – John Kugelman Apr 07 '16 at 12:47
  • At one point you said, and since removed, "**Note:** I'm not supposed to modify the logrun function.", so is it okay to modify the function? – user3439894 Apr 07 '16 at 13:03
  • @user3439894 Can you do it without modifying the function? I'd like to know if that is possible. – talamaki Apr 07 '16 at 13:10
  • I do not believe it can be done the way you have it and it needs to be modified to work. The reason I'm asking is I want to up-vote John Kugelman's answer because it does work and it's a good answer. That said, if function modification isn't allowed then as good as that answer is, it doesn't answer the question if your question is still constrained by the statement you previously made yet removed. – user3439894 Apr 07 '16 at 13:15

1 Answers1

4
logrun() {
    CMD=("$@")
    "${CMD[@]}"
}

Writing $@ without quotes combines all of the arguments into one space-separated string. "$@" with quotes keeps each argument separate and preserves whitespace.

Writing just CMD="$@" would create a simple string variable. CMD=("$@") creates an array.

Then, to expand the array, use the same syntax as you did with PARAMS: "${CMD[@]}". The quotes and the two sets of braces are all necessary. Don't leave any of them out.

By the way, if you don't need the CMD variable, it could be a lot less verbose:

logrun() {
    "$@"
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578