On 4/5/2006, at 0:16, Fred B. wrote:
However, there are some problems with this line. First, $TM_SELECTED_FILES should be quoted. Second, the eval causes the line to be re-interpreted after initial variable expansion, this is why you get an error without the single quotes.
I didn't quote $TM_SELECTED_FILES because it was not quoted in the svn bundle and I didn't have any problem even with paths with space in them. It works when quoted too, so I'll quote it anyway.
Here single spaces in file names would not be a problem. But had there been two consecutive spaces, or the use of tabs or newlines, then it would have failed.
The reason why a variable needs to be quoted is, that the shell will “split it” into multiple arguments, based on spaces, newlines, and tabs. So for example:
# $'…' is an escape-code supporting string f=$' abc \t def '
tst () { # iterate over arguments for arg in "$@"; do echo "» $arg"; done }
Now if we do:
tst $f
We get:
» abc » def
So tst receives two arguments. Had we instead done:
tst "$f"
We get:
» abc def
That is, now it gets only one argument, since bash will not split $f after expansion.
The eval prefix makes bash re-evaluate the line, after it has done the initial expansion of variables, so if we do:
eval tst "$f"
We again get:
» abc » def
So we are back to getting the variable split.
The value of TM_SELECTED_FILES is something like: 'file 1' 'file 2' 'file 3'.
This means, that even though bash does split the variable into space- separated arguments, the apostrophes remain, and eval will see these. For example:
f="'file 1' 'file 2' 'file 3'" eval tst $f
This gives:
» file 1 » file 2 » file 3
I.e. it works, but then try:
f="'file 1' 'file 2' 'file 3'" eval tst $f
And again, we get:
» file 1 » file 2 » file 3
Which is wrong. This is because after initial expansion, the line has become:
eval tst 'file 1' 'file 2' 'file 3'
And that is now being evaluated. Had we quoted $f, it would have correctly become:
eval tst 'file 1' 'file 2' 'file 3'
Don’t know if that made it any clearer. I should add that bash splits the input based on the characters found in the IFS variable (input field separator). So it is possible to change this to have it split input differently. For example, let’s say we have this function “generating” arguments:
args () { echo argument one echo argument two echo argument three }
If we do:
tst $(args)
We get 6 arguments printed, since bash will split on both the spaces and the newlines in the result from args. Here quoting won’t help, as that will turn all the output into one argument, i.e.:
tst "$(args)"
Gives us:
» argument one argument two argument three
What we can however do is, change IFS to have bash only split on newlines, and lose the quotes:
IFS=$'\n' tst $(args)
And we get:
» argument one » argument two » argument three
None of the solutions work. The first needs or has an unneeded single quote [...]
That’s what I was referring to with bash being broken. It has a problem with quotes/escapes in variable substitutions. The example I gave was for zsh.
[...] The second doesn't escape the path, as if there wasn't the dummy variable.
Sorry, it should have been:
dummy='"$HG_STYLE"'
But, I just found that $HG_STYLE was 'too' escaped in the other line (without eval), maybe that was the problem.
Not in the snippet you sent to this list.