Here is a MWE:
\documentclass{extbook} \usepackage{xspace} \usepackage{xstring} \usepackage{ifthen} \newcommand\foo[1]{% \def\tempfoo{#1}% #1% } \newcommand\separation[1]{% [\the\numexpr #1\relax ]% } \immediate\newread\myfile \newboolean{isdisplaying} \newcommand\displayfile[1]{ \edef\todisplay{\separation{#1} } \edef\aftertodisplay{\separation{#1+1} } \typeout{\todisplay} \typeout{\aftertodisplay} \setboolean{isdisplaying}{false} \immediate\openin\myfile=myfile.tex \loop\unless\ifeof\myfile \immediate\read\myfile to\fileline \ifthenelse{\equal{\aftertodisplay}{\fileline}}{\setboolean{isdisplaying}{false}}{} \ifthenelse{\boolean{isdisplaying}}{\fileline}{} \ifthenelse{\equal{\todisplay}{\fileline}}{\setboolean{isdisplaying}{true}}{} \repeat \immediate\closein\myfile } \begin{document} \displayfile{2} \end{document} Here is the content of myfile.tex:
[1] foo [2] \foo{bar} [3] baz It causes this error:
Undefined control sequence. \foo #1->\def \tempfoo {#1}#1 l.39 \displayfile{2} because of the \foo command and the \def\tempfoo{#1} line.
As @DavidCarliste said, it can be caused by a context of expansion: https://tex.stackexchange.com/a/667865/237709
But I don't understand here.
EDIT:
SO, I suppose it is the test \equal{\aftertodisplay}{\fileline} that causes the error.
[edit: that is bullshits i have written: Maybe \equal prevent the expansion of \fileline? How can I force the expansion of \fileline in this situation?]
EDIT (2): But, in my situation, the test:
\ifthenelse{\equal{\todisplay}{\protect\fileline}} is always false, while it was true with:
\ifthenelse{\equal{\todisplay}{\fileline}} However, in my example, \fileline and \protect\fileline have to give the same [2]?
In my example, \displayfile{2} with \protect\fileline produces 0 pages...
EDIT (3):
a test with
\typeout{\fileline} \typeout{\expandafter\protect\fileline} gives an interesting output:
... [2] [2] bar \foo{bar} \par \par ... EDIT (4):
I just don't understand why \protect\fileline, which displays [2], is not equal with \todisplay, while \fileline, which displays (apparently) the same [2], is equal.
EDIT (5): (@egreg answer) I can't explain why \unexpanded\expandafter{\fileline}, instead of \protect\fileline, works in the test \ifthenelse.

\ifthenelse{\equal{\aftertodisplay}{\fileline}}does edef of each argument then compares with\ifxbut the edef fails here as you can not use \foo in an edef you need \protect\foo\ifthenelse{\equal{\aftertodisplay}{\protect\fileline}it works. But why "edef" needs "protect", David?\protected@edefwhich defines\protectas\noexpand\protect\noexpandso\protect\foois\noexpand\protect\noexpand\foowhich expands to\protect\foothen the edef moves on...