[TxMt] Mercurial bundle
Allan Odgaard
throw-away-1 at macromates.com
Thu May 4 04:41:31 UTC 2006
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.
More information about the textmate
mailing list