Jump to content

Check input device is a terminal

From Rosetta Code
Task
Check input device is a terminal
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Demonstrate how to check whether the input device is a terminal or not.


Related task



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
begin
   if Isatty(Fileno(Stdin)) = 0 then
      Put_Line(Standard_Error, "stdin is not a tty.");
   else
      Put_Line(Standard_Error, "stdin is a tty.");
   end if;
end Test_tty;
Output:
$ ./test_tty 
stdin is a tty.
$ ./test_tty < /dev/null
stdin is not a tty.
terminal = isatty(0)
PRINT terminal
Output:
prompt$ bacon -q istty.bac
Converting 'istty.bac'... done, 4 lines were processed in 0.002 seconds.
Compiling 'istty.bac'... cc  -c istty.bac.c
cc -o istty istty.bac.o    -lm
Done, program 'istty' ready.
prompt$ ./istty
1
prompt$ ./istty <<<"testing"
0
Open Cons For Input As #1
' Open Cons abre los flujos de entrada (stdin) o salida (stdout) estándar 
' de la consola para leer o escribir. 

If Err Then
    Print "Input doesn't come from tt."
Else
    Print "Input comes from tty."
End If  
Close #1
Sleep


Source: siberia-man from dostips - https://www.dostips.com/forum/viewtopic.php?p=10672#p57997

(timeout /t 0 >nul 2>nul && echo Stdin is a terminal || echo Stdin is not a terminal) <nul
Output:
Stdin is not a terminal

C

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(void)
{
	puts(isatty(fileno(stdin))
		? "stdin is tty"
		: "stdin is not tty");
	return 0;
}
Output:
$ ./a.out
stdin is tty
$ ./a.out < /dev/zero
stdin is not tty
$ echo "" | ./a.out
stdin is not tty

Works with GnuCOBOL.

      *>
      *> istty, check id fd 0 is a tty
      *> Tectonics: cobc -xj istty.cob
      *>            echo "test" | ./istty
      *>
       identification division.
       program-id. istty.

       data division.
       working-storage section.
       01 rc usage binary-long.

       procedure division.
       sample-main.

       call "isatty" using by value 0 returning rc
       display "fd 0 tty: " rc

       call "isatty" using by value 1 returning rc
       display "fd 1 tty: " rc upon syserr

       call "isatty" using by value 2 returning rc
       display "fd 2 tty: " rc

       goback.
       end program istty.

DISPLAY for fd 1 is directed to SYSERR to get some output during the various trials.

Output:
prompt$ cobc -xj istty.cob
fd 0 tty: +0000000001
fd 1 tty: +0000000001
fd 2 tty: +0000000001
prompt$ echo "test" | ./istty
fd 0 tty: +0000000000
fd 1 tty: +0000000001
fd 2 tty: +0000000001
prompt$ echo "test" | ./istty >/dev/null
fd 1 tty: +0000000000
prompt$ echo "test" | ./istty 2>/dev/tty
fd 0 tty: +0000000000
fd 1 tty: +0000000001
fd 2 tty: +0000000001
prompt$ echo "test" | ./istty 2>/dev/null
fd 0 tty: +0000000000
fd 2 tty: +0000000000
Works with: SBCL
(with-open-stream (s *standard-input*)
  (format T "stdin is~:[ not~;~] a terminal~%" 
          (interactive-stream-p s)))
Output:
$ sbcl --script rc.lisp
stdin is a terminal
$ sbcl --script rc.lisp < /dev/zero
stdin is not a terminal
$ echo "" | sbcl --script rc.lisp
stdin is not a terminal
File.new("testfile").tty?   #=> false
File.new("/dev/tty").tty?   #=> true
STDIN.tty?  #=> true

D

import std.stdio;

extern(C) int isatty(int);

void main() {
    if (isatty(0))
        writeln("Input comes from tty.");
    else
        writeln("Input doesn't come from tty.");
}
Output:
C:\test
Input comes from tty.
C:\test < in.txt
Input doesn't come from tty.

Givent that ed is a non-graphical editor that's almost exclusively run in terminal, the program only needs to highlight this fact.

# by Artyom Bologov
H
a
Input from terminal!
.
p
Q
Works with: gforth version 0.7.3

In Gforth, the word "source-id" is used to determine the program source.

If you got a program file "source.f":

: ?tty source-id if ." not " then ." from terminal" ; ?tty bye

Then,

gforth source.f

in the shell will display:

Output:
not from terminal

Then,

gforth -e ': ?tty source-id if ." not " then ." from terminal" ; ?tty bye'

will display:

Output:
not from terminal

At Gforth prompt,

: ?tty source-id if ." not " then ." from terminal" ; ?tty bye

will display:

Output:
from terminal
Works with: gfortran version 14.2.0 tested on Kubuntu 25.10
Works with: ifx version 2025.2.1 tested on Kubuntu 25.10

In Fortran, all I/O is done using logical unit numbers. Units number 5 and 6 are usually reserved for standard input and standard output. If these are not redirected to read from or write to a file, the running program reads from and writes to the console resp. the command window that started the program..

However, Fortran offers no portable, standardized way to find out if a unit is connected to a file or a terminal.

Both Intel IFX and GNU gfortran compilers have the function "isatty(unitNumber)", documented as non-standard extensions.

Other compilers on other platforms may or may not have this feature.

! 
!Check input device is a terminal
! tested with Intel ifx (IFX) 2025.2.1 20250806             on Kubuntu 25.10
!             GNU Fortran (Ubuntu 15.2.0-4ubuntu4) 15.2.0   on Kubuntu 25.10
!
! This is completely non-standard. It relies on the function isatty(lun)
! which is documented as compiler-specific extension to both ifx and Gnu gfortran.
!
! U.B., January 2026
!==============================================================================
program checkTTY

implicit none

integer :: unit
logical :: isatty

! expect units 5 (standard input)  and 6 (standard output) to be terminals,
! unless it redirected to a file
! ./checktty will write that units 5 and 6 are Terminals, 
! ./checktty <a.out will give 5 is not a terminal but 6 is
! ./checktty >b.out will write to b.out, and this contains unit 5 is a terminal but unit 6 ism't
! ./checktty < a.out >b.out will write to b.out, and both units 5 and 6 are not terminals.
!
! Check units 1...10 if they are connected to a terminal.
do unit=1,10
  if (isatty (unit)) then
    write (*, '("Unit ", i2, " is a Terminal")') unit
  else
    write (*, '("Unit ", i2, " is NOT a Terminal")') unit
  endif
enddo

end program checkTTY
Output:

Unit  1 is NOT a Terminal
Unit  2 is NOT a Terminal
Unit  3 is NOT a Terminal
Unit  4 is NOT a Terminal
Unit  5 is a Terminal
Unit  6 is a Terminal
Unit  7 is NOT a Terminal
Unit  8 is NOT a Terminal
Unit  9 is NOT a Terminal
Unit 10 is NOT a Terminal

With redirected standard input:

Unit  1 is NOT a Terminal
Unit  2 is NOT a Terminal
Unit  3 is NOT a Terminal
Unit  4 is NOT a Terminal
Unit  5 is NOT a Terminal
Unit  6 is a Terminal
Unit  7 is NOT a Terminal
Unit  8 is NOT a Terminal
Unit  9 is NOT a Terminal
Unit 10 is NOT a Terminal

With standard output redirected to a file:

Unit  1 is NOT a Terminal
Unit  2 is NOT a Terminal
Unit  3 is NOT a Terminal
Unit  4 is NOT a Terminal
Unit  5 is a Terminal
Unit  6 is NOT a Terminal
Unit  7 is NOT a Terminal
Unit  8 is NOT a Terminal
Unit  9 is NOT a Terminal
Unit 10 is NOT a Terminal

And finally, with both standard input and output redirected:

Unit  1 is NOT a Terminal
Unit  2 is NOT a Terminal
Unit  3 is NOT a Terminal
Unit  4 is NOT a Terminal
Unit  5 is NOT a Terminal
Unit  6 is NOT a Terminal
Unit  7 is NOT a Terminal
Unit  8 is NOT a Terminal
Unit  9 is NOT a Terminal
Unit 10 is NOT a Terminal
include "NSLog.incl"

BeginCCode
  if (isatty(fileno(stdin)))
  NSLog( @"stdin is connected to a terminal" );
  else
  NSLog( @"stdin is NOT connected to a terminal" );
EndC

HandleEvents
Output:
stdin is NOT connected to a terminal


package main

import (
    "golang.org/x/crypto/ssh/terminal"
    "fmt"
    "os"
)

func main() {
    if terminal.IsTerminal(int(os.Stdin.Fd())) {
        fmt.Println("Hello terminal")
    } else {
        fmt.Println("Who are you?  You're not a terminal.")
    }
}
Output:
> hello
Hello terminal
> hello </dev/null
Who are you?  You're not a terminal.


Example uses unix package:

module Main (main) where
 
import           System.Posix.IO (stdInput)
import           System.Posix.Terminal (queryTerminal)
 
main :: IO ()
main = do
    isTTY <- queryTerminal stdInput
    putStrLn $ if isTTY
                then "stdin is TTY"
                else "stdin is not TTY"
(if (os/isatty stdin)
  (print "The input device is a terminal.")
  (print "The input device is not a terminal."))
/* Check input device is a terminal, in Jsish */
;Interp.conf().subOpts.istty;

/*
=!EXPECTSTART!=
Interp.conf().subOpts.istty ==> false
=!EXPECTEND!=
*/
Output:
prompt$ jsish
Jsish interactive: see 'help [cmd]' or 'history'.  \ cancels > input.  ctrl-c aborts running script.
jsi> Interp.conf().subOpts.istty;
true
jsi>
prompt$ jsish --U checkInputDevice.jsi
Interp.conf().subOpts.istty ==> false
if isa(STDIN, Base.TTY)
    println("This program sees STDIN as a TTY.")
else
    println("This program does not see STDIN as a TTY.")
end
Output:
This program sees STDIN as a TTY.
Works with: Ubuntu version 14.04
// Kotlin Native version 0.5

import platform.posix.*

fun main(args: Array<String>) {
    if (isatty(STDIN_FILENO) != 0)
        println("stdin is a terminal")
    else
        println("stdin is not a terminal") 
}
Output:
stdin is a terminal

You can get isatty from lua posix

local posix = require"posix"
print(
 posix.unistd.isatty(posix.stdio.fileno(io.stdin))
 and "stdin is a terminal"
 or "stdin is not a terminal"
)

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

def isTerm = System.Console.IsInputRedirected;

Using function "isatty" of standard module "terminal" which accepts a File as argument.

import terminal

echo if stdin.isatty: "stdin is a terminal" else: "stdin is not a terminal"
Output:
Command: ./check_input_dev
Result: stdin is a terminal
Command: ./check_input_dev <somefile
Result: stdin is not a terminal
Works with: Nushell version 0.96.1
$'stdin is a terminal: (is-terminal -i)'
let () =
  print_endline (
    if Unix.isatty Unix.stdin
    then "Input comes from tty."
    else "Input doesn't come from tty."
  )

Testing in interpreted mode:

$ ocaml unix.cma istty.ml
Input comes from tty.
$ echo "foo" | ocaml unix.cma istty.ml
Input doesn't come from tty.
(define (isatty? fd) (syscall 16 fd 19))
(print (if (isatty? stdin)
   "Input comes from tty."
   "Input doesn't come from tty."))
##
uses system;
system.Console.IsInputRedirected.println;
Output:
C:\PABCWork.NET\Output>checkinput.exe
False
C:\PABCWork.NET\Output>echo test | checkinput.exe
True
use strict;
use warnings;
use 5.010;
if (-t) {
    say "Input comes from tty.";
}
else {
    say "Input doesn't come from tty.";
}
$ perl istty.pl
Input comes from tty.
$ true | perl istty.pl
Input doesn't come from tty.
without js -- (no input redirection in a browser!)
printf(1,"stdin:%t, stdout:%t, stderr:%t\n",{isatty(0),isatty(1),isatty(2)})
Output:
C:\Program Files (x86)\Phix>p test
stdin:true, stdout:true, stderr:true
C:\Program Files (x86)\Phix>echo hello | p test
stdin:false, stdout:true, stderr:true
void main()
{
    if(Stdio.Terminfo.is_tty())
	write("Input comes from tty.\n");
    else
        write("Input doesn't come from tty.\n");
}
Output:
$ ./istty.pike
Input comes from tty.
$ echo | ./istty.pike
Input doesn't come from tty.

Works with Bash shell on Linux but can't vouch for anything else.

os.execute("test -t 0 ; echo $? > tmp")
os.sleep(1)
local res = io.contents("tmp"):rstrip()
print($"Input device is a terminal? {res == "0"}")
os.remove("tmp")
Output:
Input device is a terminal? true

Alternatively, for POSIX systems only:

local ffi = require "pluto:ffi"
local lib = ffi.open("libc.so.6")
lib:cdef[[ int isatty(int fd); ]]

local res = lib.isatty(0)
print($"Input device is a terminal? {res == 1}")
Output:
Same as before.
from sys import stdin
if stdin.isatty():
    print("Input comes from tty.")
else:
    print("Input doesn't come from tty.")
$ python istty.py
Input comes from tty.
$ true | python istty.py
Input doesn't come from tty.
Translation of: Python
  [ $ |from sys import stdin
to_stack( 1 if stdin.isatty() else 0)|
    python ]                            is ttyin ( --> b )     

  ttyin if 
    [ say "Looks like a teletype." ] 
  else 
    [ say "Not a teletype." ]
Output:
Looks like a teletype.
(terminal-port? (current-input-port))

(formerly Perl 6)

Works with: Rakudo version 2015.12
say $*IN.t ?? "Input comes from tty." !! "Input doesn't come from tty.";
$ raku istty.raku
Input comes from tty.
$ true | raku istty.raku
Input doesn't come from tty.

So far this detection is not available. User input is not expected, when Rebol is started with `--cgi` flag, which may be detected in a script like:

either system/options/flags/cgi [
    print "CGI mode - no terminal"
    ;; get input data
    probe data: read system/ports/input
][  print "not CGI mode" ]

Since version 3.21.13 one can use `tty?` function.

/*REXX program determines if input comes from terminal or standard input*/

if queued()  then say 'input comes from the terminal.'
             else say 'input comes from the (stacked) terminal queue.'

                                       /*stick a fork in it, we're done.*/
# Project  : Check input device is a terminal
 
load "stdlib.ring"

if isWindows()
   write("mycmd.bat","
   @echo off
    timeout 1 2>nul >nul
    if errorlevel 1 (
       echo input redirected
        ) else (
       echo input is console
       )
       ")
    see SystemCmd("mycmd.bat")
ok

Output:

input redirected

Example from the docs.

File.new("testfile").isatty   #=> false
File.new("/dev/tty").isatty   #=> true
/* Uses C library interface */

extern crate libc;

fn main() {
    let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    if istty {
        println!("stdout is tty");
    } else {
        println!("stdout is not tty");
    }
}
Works with: Ubuntu version 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(STDIN_FILENO) == 1
    }
    catch {
      case ignore: Throwable =>
        ignore.printStackTrace()
        false

    }
  }

    println("tty " + apply(true))
}
val stdinRefersToTerminal : bool = Posix.ProcEnv.isatty Posix.FileSys.stdin

Tcl automatically detects whether stdin is coming from a terminal (or a socket) and sets up the channel to have the correct type. One of the configuration options of a terminal channel is -mode (used to configure baud rates on a real serial terminal) so we simply detect whether the option is present.

if {[catch {fconfigure stdin -mode}]} {
    puts "Input doesn't come from tty."
} else {
    puts "Input comes from tty."
}

Demonstrating:

$ tclsh8.5 istty.tcl 
Input comes from tty.
$ tclsh8.5 istty.tcl </dev/null
Input doesn't come from tty.
#!/bin/sh

if [ -t 0 ]
then echo "Input is a terminal"
else echo "Input is NOT a terminal"
fi
import "io" for Stdin

System.print("Input device is a terminal? %(Stdin.isTerminal ? "Yes" : "No")")
Output:
Input device is a terminal? Yes

POSIX only.

import "unistd.h"

fn main() {
    let res = isatty(fileno(stdin)) ? "true" : "false";
    println "Input device is a terminal? {res}";
}
Output:
Input device is a terminal? true

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

const S_IFCHR=0x2000;
fcn S_ISCHR(f){ f.info()[4].bitAnd(S_IFCHR).toBool() }
S_ISCHR(File.stdin).println();
Output:
$ zkl bbb  # from the command line
True
$ zkl bbb < bbb.zkl
False
$ cat bbb.zkl | zkl bbb
False
Cookies help us deliver our services. By using our services, you agree to our use of cookies.