Search code examples
macosdockertailtty

Carriage-returns are not applied when running `tail -f` in the background while running `docker exec -it` in the foreground


When I run tail -f in the background and docker exec -it in the foreground, the outputs of tail-command are corrupted.

For example, when I run the following commands:

$ tail -f log.txt &
$ docker exec -it my-container /bin/bash

and I append the following 3 lines to log.txt:

cat
dog
bird

then I get the following strange outputs:

root@4083b121d1793:~# cat
                         dog
                            bird

Notice the line breaks. I'm guessing carriage returns are not applied.

Why does this strange behavior occur? Is there any solution?


Update

Versoins:

  • Docker Desktop for Mac 3.2.1
  • Docker Engine 20.10.5

Solution

  • This seems to happen because of the call to MakeRaw() in the docker CLI. The docs explain that the function turns the file descriptor (stdin) into "raw mode" so it can be restored to its original state once the terminal session ends. These function calls all happen when setting up the interactive exec session in the CLI in hijack.go in the docker/cli source code.

    This is where that happens in the source code. You can see from this that if you set the NORAW environment variable, you get the normal output:

    // SetRawTerminal sets raw mode on the input terminal
    func (i *In) SetRawTerminal() (err error) {
        if os.Getenv("NORAW") != "" || !i.commonStream.isTerminal {
            return nil
        }
        i.commonStream.state, err = term.SetRawTerminal(i.commonStream.fd)
    

    Here is how I tested this, setting the variable NORAW when running the exec command:

    Terminal 1:

    $ tail -f log.txt
    $ NORAW=1 docker exec -it containername /bin/bash
    root@docker:/work$
    

    Terminal 2:

    $ echo -e "something\nto\ntest" >> log.txt
    

    Back in Terminal 1:

    root@docker:/work$ something
    to
    test
    

    I had reproduced exactly what you had before but I happened to be testing on Windows and in WSL2.

    However, when NORAW is set, you will not be restored as usual to your original terminal session. After ^D or exit, you will the last terminal prompt will immediately be pasted where your cursor is:

    root@docker:/work$   $
    ^ docker prompt      ^ original terminal prompt session