Quoting?

  • This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.
#1
The second ECHO command below seems to figure out the quoting OK. But both IF and IFF choke on it. What's up with that?
Code:
v:\> echo 2018xxx > "v:\a b"

v:\> echo "%@execstr[grep 2018 "v:\a b"]"
"2018xxx"

v:\> if "%@execstr[grep 2018 "v:\a b"]" NE "" echo yes
TCC: Syntax error "@execstr[grep 2018 "v:\a"
Usage : IF [/I] [NOT] condition [.AND. | .OR. | .XOR. [NOT] condition ...] command

v:\> iff "%@execstr[grep 2018 "v:\a b"]" NE "" then & echo yes & endiff
TCC: Syntax error "@execstr[grep 2018 "v:\a"
Usage : IFF [NOT] condition [.AND. | .OR. | .XOR. [NOT] condition ...] THEN & commands
yes
TCC: Unknown command "endiff"
 
#3
TCC is looking to expand the first argument (so IF / IFF can compare it to the next argument). Because you put a quote at the beginning, it terminates at the first white space following the next closing quote. So the first argument is:

"%@execstr[grep 2018 "v:\a

which the variable expansion does not like at all.
The expression
Code:
"%@execstr[grep 2018 "v:\a b"]"
works everywhere else I tried it. It's a shame that IF and IFF have to be different.
 

rconn

Administrator
Staff member
May 14, 2008
10,291
90
#4
1) 25+ year old behavior.
2) It works everywhere (not really, but almost everywhere) else because the expression is parsed & expanded before being passed to the command (which won't work for IF / IFF, as they wouldn't have any idea which arguments to compare).
3) IF and IFF have to be different if you want to put variables in your comparisons.
4) Don't use double quotes to delimit your arguments that contain embedded double quotes, and you won't have any problems.
5) Why in the world are you using @execstr to do this? That's (another) obsolete function. It was useful for DOS.
 
#6
Good question! And could you do it otherwise with a single line of code? @EXECSTR is (quite) a convenience; it almost always saves a line or two of code. To avoid @EXECSTR, you'd basically have to do what @EXECSTR does ... send the output of a command to a temp file and check the file. Here, FFIND itself will take care of deleting the temp file.
Code:
alias >&> nul |! ffind /t"=" /f > nul
iff %_ffind_matches == 0 then & echo There are no aliases. & endiff
Note that with the above, the in-process pipe is required because, otherwise, the _FFIND_* variables would be lost.

While these two strategies (below) seem quite different, there's no difference in speed. As noted above, using @EXECSTR involves less typing.
Code:
v:\> type ffindtest.btm
timer /q
do i=1 to 100
        iff "%@execstr[alias >&> nul]" == "" then & noop & endiff
enddo
timer

timer /q
do i=1 to 100
        alias >&> nul |! (ffind /t"=" /f > nul)
        iff %_ffind_matches == 0 then & noop & endiff
enddo
timer


v:\> ffindtest.btm
Timer 1 off: 13:15:53  Elapsed: 0:00:03.12
Timer 1 off: 13:15:56  Elapsed: 0:00:03.12