When I \immediate\write\somefile{foo}, TeX writes foo to the file open in the output stream \somefile, but it also goes to the next line. (The resulting file has 4 bytes.)

Since I am writing files and reading them as the body of some environments, it would be nice if I could disable this extra new-line character.

The main problem is when I write foo^^M at the end of a file, and the newline I write combines with the 'default' one: it leads to a spurious \par, which breaks short macros (and the align environment).

So, is it possible to avoid going to the next line using \write?

  • Could you post a full minimal example?
    – Joseph Wright
    Jan 1, 2011 at 20:59
  • That's trickier than I thought at first: I need to both include the code for verbatim-writing-to-file, and the code for reading from the file. I'll try to do this tomorrow. Jan 1, 2011 at 22:15

3 Answers 3


To answer your question: No, you cannot avoid the new line character that gets inserted. See below for how I arrived at this conclusion.

I find the source code to TeX very confusing so it's certainly possible that I'm missing something here. The way I read this, \write is implemented as an extension, not because it's actually an extension, just that Knuth wanted to give an example of writing one. In particular, \write is implemented as a whatsit node:

@<Implement \.{\\write}@>=
begin k:=cur_cs; new_write_whatsit(write_node_size);@/
cur_cs:=k; p:=scan_toks(false,false); write_tokens(tail):=def_ref;

Rather than track down exactly how whatsits are treated, it suffices to look for the implementation of \immediate since \immediate\write performs the write immediately. The relevant portion of the code is the following.

@<Implement \.{\\immediate}@>=
begin get_x_token;
if cur_cmd=extension then begin
    if cur_chr<=close_node then
      begin p:=tail; do_extension; {append a whatsit node}
      out_what(tail); {do the action immediately}
      flush_node_list(tail); tail:=p; link(p):=null;

Clearly, this is appending a whatsit node, executing the node, flushing it (presumably freeing the memory associated with it), and then restoring the linked list to what it was before it appended the node. What we're interested in here is out_what. Again, the relevant portion follows.

procedure out_what(@!p:pointer);
var j:small_number; {write stream number}
begin case subtype(p) of
open_node,write_node,close_node:@<Do some work that has been queued up
  for \.{\\write}@>;


@<Do some work that has been queued up...@>=
if not doing_leaders then
  begin j:=write_stream(p);
  if subtype(p)=write_node then write_out(p)

Obviously, we want write_out.

procedure write_out(@!p:pointer);
var old_setting:0..max_selector; {holds print |selector|}
@!old_mode:integer; {saved |mode|}
@!j:small_number; {write stream number}
@!q,@!r:pointer; {temporary variables for list manipulation}
begin @<Expand macros in the token list
  and make |link(def_ref)| point to the result@>;
old_setting:=selector; j:=write_stream(p);
if write_open[j] then selector:=j
else  begin {write to the terminal if file isn't open}
  if (j=17)and(selector=term_and_log) then selector:=log_only;
token_show(def_ref); print_ln;
flush_list(def_ref); selector:=old_setting;

The global variable selector is used to determine where output should be directed. In the case of a \write to a file, it will be a number 0–15. The line if write_open[j] then selector:=j sets the selector to j. token_show(def_ref) prints the tokens pointed to by def_ref based on selector. Then print_ln is called.

@ To end a line of text output, we call |print_ln|.

@<Basic print...@>=
procedure print_ln; {prints an end-of-line}
begin case selector of
term_and_log: begin wterm_cr; wlog_cr;
  term_offset:=0; file_offset:=0;
log_only: begin wlog_cr; file_offset:=0;
term_only: begin wterm_cr; term_offset:=0;
no_print,pseudo,new_string: do_nothing;
othercases write_ln(write_file[selector])
end; {|tally| is not affected}

As that comment says, print_ln is used to end a line of text.

It's actually at this point that I get stuck. I can't find a definition for write_ln. My best guess is that WEB removes underscores so that write_ln becomes the pascal writeln which the web2c binary fixwrites converts. From the top of fixwrites.c:

/* fixwrites -- convert Pascal write/writeln's into fprintf's or putc's.
   Originally by Tim Morgan, October 10, 1987.  */

At any rate, the very first function in the generated pdftex0.c is

println ( void )
  switch ( selector )
    /* elided cases 17 through 21 */
    putc ('\n', writefile [selector ]);
  • @TH : impressive!! (I can track things down in La/TeX code, but definitely not in C or WEB.) Now I know why Knuth does not talk about customizing this. And I will just need to strip my input from trailing newlines. Thanks for the info. Jan 2, 2011 at 9:35

Thinking about it, I suspect you are running into the followin

Each message given with \immediate\write starts on a new line; the user can force a new line in the message by including the character with number \newlinechar. This parameter also works in \message.

(TeX by Topic, as so often.) To keep control of lines, you need to use only one \write and use ^^J where you want a new line.

  • No, I am asking in some sense for the opposite of \newlinechar: how does TeX decide what character to append at each write command? --- cf. page 227 of the TeXbook: " \immediate\write16 differs from \message in that \write prints the text on a line by itself " --- I would like a \message\file if it is possible. --- It is true that a solution to my problem is to trim what I write to the file: remove my trailing \newlinechar, and leave the automatic newline alone. That's a bit tricky since I don't always have a trailing newline, and accessing the last character of a string is hard. Jan 1, 2011 at 22:12

This isn't a direct answer, but since you say you're reading the files back into TeX, you could try appending \relax to the end of what you're writing out: \immediate\write\somefile{foo\relax}. The \relax will swallow all the following space, which sounds like it will solve the symptoms of your problem, though not the source. Obviously, it's not a perfect solution, but it might be good enough. (My guess at an actual solution was \newlinechar=-1, but no change I made to \newlinechar seemed to do anything.)

  • 1
    In fact, I am currently (prepending and) appending \relax. But it breaks down when inside a verbatim environment: \relax is typeset. Admittedly, I don't care: given the precise context, there is absolutely no reason that my code would ever be used for inclusion in a verbatim. But still, not completely satisfactory. --- \newlinechar changes what character is translated by TeX to a new line in the output. But the final new line is just created from nowhere by TeX, it seems (I guess the solution is to dive into the TeX source and check ;-)). Jan 1, 2011 at 23:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .