⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

{{draft task}} [[Category:Hardware]] [[Category:Terminal control]] [[Category:Initialization]] {{omit from|TI-83 BASIC|Output device is always either a terminal or created by the program}}

;Task: Demonstrate how to check whether the output device is a terminal or not.

;Related task:

  • [[Check input device is a terminal]]


{{works with|GNAT}} We use the interface to C library functions isatty() and fileno().

with Ada.Text_IO;          use Ada.Text_IO;
with Interfaces.C_Streams; use Interfaces.C_Streams;

procedure Test_tty is
   if Isatty(Fileno(Stdout)) = 0 then
      Put_Line(Standard_Error, "stdout is not a tty.");
      Put_Line(Standard_Error, "stdout is a tty.");
   end if;
end Test_tty;


$ ./test_tty
stdout is a tty.
$ ./test_tty > /dev/null
stdout is not a tty.


Use isatty() on file descriptor to determine if it's a TTY. To get the file descriptor from a FILE* pointer, use fileno:

#include <unistd.h>   // for isatty()
#include <stdio.h>    // for fileno()

int main()
          ? "stdout is tty"
          : "stdout is not tty");
    return 0;


$ ./a.out
stdout is tty

$ ./a.out > tmp
$ cat tmp
stdout is not tty

$ ./a.out | cat
stdout is not tty



#if _WIN32
#include <io.h>
#define ISATTY _isatty
#define FILENO _fileno
#include <unistd.h>
#define ISATTY isatty
#define FILENO fileno

#include <iostream>

int main() {
    if (ISATTY(FILENO(stdout))) {
        std::cout << "stdout is a tty\n";
    } else {
        std::cout << "stdout is not a tty\n";

    return 0;


using System;

namespace CheckTerminal {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine("Stdout is tty: {0}", Console.IsOutputRedirected);

Common Lisp

{{Works with|SBCL}}

(with-open-stream (s *standard-output*)
  (format T "stdout is~:[ not~;~] a terminal~%"
          (interactive-stream-p s)))


$ sbcl --script rc.lisp
stdout is a terminal
$ sbcl --script rc.lisp | cat
stdout is not a terminal
$ sbcl --script rc.lisp > foo.txt
$ cat foo.txt
stdout is not a terminal

{{Works with|ECL}} We use the interface to C library functions isatty() and fileno(). It needs to be compiled to be executed.

(ffi:clines "
    #include <sys/ioctl.h>
    #include <unistd.h>
    int ttyPredicate() {
      return isatty(fileno(stdout));

    ("ttyPredicate" c-ttyp)
    () :returning :int)

(defun tty-p()
  (if (= 1 (c-ttyp))

(format T "stdout is~:[ not~;~] a terminal~%" (tty-p))

Compilation can be done with the following commands :

ecl --eval '(compile-file "file.lisp" :system-p t)' --eval '(quit)'

ecl --eval '(c:build-program "is-tty" :lisp-files (list "file.o"))' --eval '(quit)'


$ ./is-tty
stdout is a terminal
$ ./is-tty  | cat -
stdout is not a terminal


File.new("testfile").tty?   #=> false
File.new("/dev/tty").tty?   #=> true
STDOUT.tty?  #=> true


import std.stdio;

extern(C) int isatty(int);

void main() {
    writeln("Stdout is tty: ", stdout.fileno.isatty == 1);


Stdout is tty: true
prompt>a.out > out.txt
Stdout is tty: false


You have to know 1 is the correct file descriptor number:

IN: scratchpad USE: unix.ffi
IN: scratchpad 1 isatty

--- Data stack:


{{libheader|Go sub-repositories}}

package main

import (

func main() {
    if terminal.IsTerminal(int(os.Stdout.Fd())) {
        fmt.Println("Hello terminal")
    } else {
        fmt.Println("Who are you?  You're not a terminal.")


> hello
Hello terminal
> hello | cat
Who are you?  You're not a terminal.


module Main where

-- requires the unix package
-- https://hackage.haskell.org/package/unix
import System.Posix.Terminal (queryTerminal)
import System.Posix.IO (stdOutput)

main :: IO ()
main = do
  istty <- queryTerminal stdOutput
    (if istty
       then "stdout is tty"
       else "stdout is not tty")


$ runhaskell istty.hs
stdout is tty
$ runhaskell istty.hs | cat
stdout is not tty


node -p -e "Boolean(process.stdout.isTTY)"




J does not have a concept of an "output device", so we approximate that by seeing whether we have bothered to define a the code which typically does graphical output.

The use of the phrase "output device" suggests that we are thinking about something like the unix isatty command. Here, stdout might be a file or might be a terminal. But in J we are often hosting our own user interaction environment. It's not uncommon for a J user to be on a web page where hitting enter sends a form request to a J interpreter which in turn composes an updated html presentation of current state which it sends to the browser. Or, the J user might be talking to a Java program which similarly wraps the J session (though this is older technology at this point). Or, the J user might be interacting with Qt. Or, sure, we might be talking to a tty and J might be sending its output straight to the tty. (But we can't know if that tty is hosted in emacs, running under control of a script on a remote machine via ssh, talking directly to a human user who happens to be in direct control of the session, or whatever else...)

The point being that in the general case the J programmer cannot know whether the concept of "terminal" has any relevance to the user.

But, like everyone else, we can certainly use heuristics.

But, correctness requires us to keep in mind that these will only be heuristics, and will sometimes be incorrect (hopefully not often enough to matter a lot...).


if isa(STDOUT, Base.TTY)
    println("This program sees STDOUT as a TTY.")
    println("This program does not see STDOUT as a TTY.")


This program sees STDOUT as a TTY.


{{Works with|Ubuntu|14.04}}

// Kotlin Native version 0.5

import platform.posix.*

fun main(args: Array<String>) {
    if (isatty(STDOUT_FILENO) != 0)
        println("stdout is a terminal")
        println("stdout is not a terminal")


stdout is a terminal


There is no explicit way (ie isatty())to do this; however, if we ''assume'' that standard out ''is'' a terminal, we can check if the output stream has been redirected (presumably to something other than a terminal).

## OCaml

let () =
  print_endline (
    if Unix.isatty Unix.stdout
    then "Output goes to tty."
    else "Output doesn't go to tty."

Testing in interpreted mode:

$ ocaml unix.cma istty.ml
Output goes to tty.

$ ocaml unix.cma istty.ml > tmp
$ cat tmp
Output doesn't go to tty.

$ ocaml unix.cma istty.ml | cat
Output doesn't go to tty.


The -t function on a filehandle tells you whether it's a terminal.

$ perl -e "warn -t STDOUT ? 'Terminal' : 'Other'"
$ perl -e "warn -t STDOUT ? 'Terminal' : 'Other'" > x.tmp

Perl 6

{{works with|Rakudo|2015.12}} The .t method on a filehandle tells you whether it's going to the terminal. Here we use the note function to emit our result to standard error rather than standard out.

$ perl6 -e 'note $*OUT.t'
$ perl6 -e 'note $*OUT.t' >/dev/null


if(posix_isatty(STDOUT)) {
    echo "The output device is a terminal".PHP_EOL;
} else {
    echo "The output device is NOT a terminal".PHP_EOL;


Pretty much the same as [[Check input device is a terminal#Python]].

from sys import stdout
if stdout.isatty():
    print 'The output device is a teletype. Or something like a teletype.'
    print 'The output device isn\'t like a teletype.'


(terminal-port? (current-output-port))


{{works with|PC/REXX under DOS or in a DOS window under MS Windows}} {{works with|Personal REXX under DOS or in a DOS window under MS Windows}} {{works with|Regina in a DOS window under MS Windows}} Programming note: The comment about the REXX statements have to be on one line isn't quite true,

but because the REXX special variable '''SIGL''' is defined where it's executed, it makes coding simpler.

'''SIGL''' is set to the REXX statment number where: :::* a '''CALL''' statement is used :::* a ''function'' is invoked :::* a '''SIGNAL''' statement is used Method used: since REXX has no direct way of determining if the STDIN is a terminal or not, the REXX code (below)

actually ''raises'' (which is no way to run a railroad) a syntax error when attempting to read the 2nd line from STDIN,

which causes a routine (named '''syntax:''') to get control, determines where the syntax error occurred, and returns an

appropriate string indicating if STDIN is a '''terminal''' (or '''other''').

Note that under VM/CMS, this can be accomplished with a (host) command within REXX and then examining the results.

On IBM mainframes, a user can have STDIN defined, but the terminal can be ''disconnected''.

/*REXX program determines if the   STDIN   is a   terminal   or  other. */
signal on syntax                       /*if syntax error, jump──► SYNTAX*/
say  'output device:'  testSTDIN()     /*displays terminal ──or── other */
exit                                   /*stick a fork in it, we're done.*/
/*──────────────────────────────────TESTSTDIN subroutine────────────────*/
testSTDIN: syntax.=1; signal .; .: z.=sigl; call linein ,2;  ..: syntax.=0
return z..                             /* [↑]   must all be on one line.*/
/*──────────────────────────────────SYNTAX subroutine───────────────────*/
syntax:  z..='other'                   /*when SYNTAX occur,  come here. */
if syntax.  then do                    /*handling  STDIN  thingy error? */
                 if sigl==z.  then z..='terminal'; signal ..   /*stdin ?*/
                 end                   /* [↑]   can't use a RETURN here.*/

     /* ··· handle other REXX syntax errors here ···   */


output device: terminal


f = File.open("test.txt")
p f.isatty          # => false
p STDOUT.isatty     # => true


/* Uses C library interface */

extern crate libc;

fn main() {
    let istty = unsafe { libc::isatty(libc::STDOUT_FILENO as i32) } != 0;
    if istty {
        println!("stdout is tty");
    } else {
        println!("stdout is not tty");


{{Works with|Ubuntu|14.04}}

import org.fusesource.jansi.internal.CLibrary._

object IsATty  extends App {

  var enabled = true

  def apply(enabled: Boolean): Boolean = {
    // We must be on some unix variant..
    try {
      enabled && isatty(STDOUT_FILENO) == 1
    catch {
      case ignore: Throwable =>


    println("tty " + apply(true))


To detect whether output is going to a terminal in Tcl, you check whether the stdout channel looks like a serial line (as those are indistinguishable from terminals). The simplest way of doing that is to see whether you can read the -mode or -xchar channel options, which are only present on serial channels:

set toTTY [dict exists [fconfigure stdout] -mode]
puts [expr {$toTTY ? "Output goes to tty" : "Output doesn't go to tty"}]

At the system call level, when Tcl is setting up the channels that correspond to the underlying stdout (and stdin and stderr) file descriptors, it checks whether the channels are network sockets (with getsockname()) or serial lines (with isatty()). This allows Tcl scripts to find out information about their calling environment (e.g., when they are run from inetd) with minimal code. {{out|Demonstrating}} Assuming that the above script is stored in the file istty.tcl:

$ tclsh8.5 istty.tcl
Output goes to tty
$ tclsh8.5 istty.tcl | cat
Output doesn't go to tty

Channel type discovery with older Tcl versions

Before Tcl 8.4, this discovery process is impossible; stdout always looks like it is going to a file. With 8.4, you can discover the channel type but you need slightly different (and less efficient, due to the thrown error in the non-tty case) code to do it.

set toTTY [expr {![catch {fconfigure stdout -mode}]}]

UNIX Shell


if [ -t 1 ]
   echo "Output is a terminal"
   echo "Output is NOT a terminal" >/dev/tty

Visual Basic .NET


Module Module1

    Sub Main()
        Console.WriteLine("Stdout is tty: {0}", Console.IsOutputRedirected)
    End Sub

End Module


On Unix, check to see if stdout's st_mode is a character device.

const S_IFCHR=0x2000;
fcn S_ISCHR(f){ f.info()[4].bitAnd(S_IFCHR).toBool() }


$ zkl bbb  # from the command line
$ zkl bbb | more
$ zkl bbb > foo.txt
$ cat foo.txt