"Stdin: Is Not a Tty" from Cronjob

stdin: is not a tty from cronjob

You actually have two questions here.

  1. Why it prints stdin: is not a tty?

This warning message is printed by bash -l. The -l (--login) options asks bash to start the login shell, e.g. the one which is usually started when you enter your password. In this case bash expects its stdin to be a real terminal (e.g. the isatty(0) call should return 1), and it's not true if it is run by cron—hence this warning.

Another easy way to reproduce this warning, and the very common one, is to run this command via ssh:

$ ssh user@example.com 'bash -l -c "echo test"'
Password:
stdin: is not a tty
test

It happens because ssh does not allocate a terminal when called with a command as a parameter (one should use -t option for ssh to force the terminal allocation in this case).


  1. Why it did not work without -l?

As correctly stated by @Cyrus in the comments, the list of files which bash loads on start depends on the type of the session. E.g. for login shells it will load /etc/profile, ~/.bash_profile, ~/.bash_login, and ~/.profile (see INVOCATION in manual bash(1)), while for non-login shells it will only load ~/.bashrc. It seems you defined your http_proxy variable only in one of the files loaded for login shells, but not in ~/.bashrc. You moved it to ~/.wgetrc and it's correct, but you could also define it in ~/.bashrc and it would have worked.

Crontab does not work properly

The error message you see already tries to explain what's wrong. As you specified -t to the exec command, it tries to allocate a TTY. When run from cron, there is no pseudo-TTY available and thus it fails.

Try to change your script to this:

#!/bin/bash
/usr/bin/docker restart container_name 2>/dev/null
/usr/bin/docker exec -i container_name /path/launcher.sh 2>/dev/null

FYI: There are a lot of questions regarding cron and TTY here. For example, this one explains the problem pretty well: "stdin: is not a tty" from cronjob

Error The input device is not a TTY

Remove the -it from your cli to make it non interactive and remove the TTY. If you don't need either, e.g. running your command inside of a Jenkins or cron script, you should do this.

Or you can change it to -i if you have input piped into the docker command that doesn't come from a TTY. If you have something like xyz | docker ... or docker ... <input in your command line, do this.

Or you can change it to -t if you want TTY support but don't have it available on the input device. Do this for apps that check for a TTY to enable color formatting of the output in your logs, or for when you later attach to the container with a proper terminal.

Or if you need an interactive terminal and aren't running in a terminal on Linux or MacOS, use a different command line interface. PowerShell is reported to include this support on Windows.


What is a TTY? It's a terminal interface that supports escape sequences, moving the cursor around, etc, that comes from the old days of dumb terminals attached to mainframes. Today it is provided by the Linux command terminals and ssh interfaces. See the wikipedia article for more details.

To see the difference of running a container with and without a TTY, run a container without one: docker run --rm -i ubuntu bash. From inside that container, install vim with apt-get update; apt-get install vim. Note the lack of a prompt. When running vim against a file, try to move the cursor around within the file.

Pseudo-terminal will not be allocated because stdin is not a terminal

Try ssh -t -t(or ssh -tt for short) to force pseudo-tty allocation even if stdin isn't a terminal.

See also: Terminating SSH session executed by bash script

From ssh manpage:

-T      Disable pseudo-tty allocation.

-t Force pseudo-tty allocation. This can be used to execute arbitrary
screen-based programs on a remote machine, which can be very useful,
e.g. when implementing menu services. Multiple -t options force tty
allocation, even if ssh has no local tty.

Rails cronjob problems

Something is trying to read or operate on STDIN in a way that expects it to be a TTY.

If this doesn't happen on the other machine it is likely something in your rcfile (which is being loaded because you've indicated you want bash to act as a login shell with -l).

Check the ~/.bashrc and comparable files on the new machine.

Knowing a python script has something to read from stdin when launched by crontab

As Nullman already wrote in a comment it is better to check your command line options to decide if you want to try stdin or not.

Short summary: You cannot safely guess if you should read data from stdin by checking stdin. You should only rely on checking the command line to find out what is expected.

For example cat will use stdin only if no input file was specified as a command line argument or if the special file name - was specified.


All the tests in your examples will work in certain conditions only and will not work in other cases.

Checking if stdin is a TTY does not help. It will only tell you if it is connected to a terminal. Your script can get input from a terminal if the user types something or if it is a pseudo-terminal connected to something else. Your script can also get input from stdin if it is not connected to a terminal but to something else (pipe, file, socket,...)

Checking if stdin is a FIFO is also wrong because you can read data both from a pipe/fifo or from something else (file, socket, terminal,...).

Using select will not tell you if there is any data, but only if a read will not block. It also will not block on EOF. To distinguish these cases you would have to check the result of a read from stdin. Without a delay/timeout it might also tell you that a read would block if the data is not yet available.

There are more ways to use the script:

Instead of cat myInput | ./myscript.py you could also use ./myscript.py < myInput. In the first case stdin will be a pipe, in the second case a file.

Or imagine ./myscript.py < /dev/null. This will return EOF condition on the first read.

Or ./myscript.py <&- which will close stdin leading to an error when you try to read from it.

If stdin is connected to a terminal a read might block if the user does not enter anything. This would happen if you call ./myscript.py. You could use select to find out if data is available now, but you cannot find out if the user will enter data later. So your script does not know the intention of the user.

MySQL Git Bash winpty mysqldump stdout is not a tty and stdin is not a tty

The error is actually from winpty because you are trying to redirect output to a file and it expects a terminal for interactive use.

Normally, native Git bash commands like git, ssh and all output redirection like node --version | clip should work without winpty.

These mysql commands are different in that they need interactive input (for password entry) before redirecting their output. In order to correctly work we need to make them run through winpty without using output redirection.

$ winpty mysqldump -u USER -p DB_NAME -r OUTPUT.sql
Enter password: ******

--result-file=file_name, -r file_name

Direct output to a given file. This option should be used on Windows to prevent newline "\n" characters from being converted to "\r\n" carriage return/newline sequences. The result file is created and its previous contents overwritten, even if an error occurs while generating the dump.

mysqldump screenshot

$ winpty mysql -u USER -p DB_NAME
Enter password: ******

mysql> source INPUT.sql

mysql screenshot



Related Topics



Leave a reply



Submit