Check output device is a terminal: Difference between revisions

From Rosetta Code
Content added Content deleted
m (moved Categorys to top)
m (moved Categorys to top / Category:Hardware)
Line 1: Line 1:
{{draft task}} [[Category:Terminal control]]
{{draft task}} [[Category:Hardware]] [[Category:Terminal control]] [[Category:Initialization]]

The task is to demonstrate how to check whether the output device is a terminal or not.
The task is to demonstrate how to check whether the output device is a terminal or not.



Revision as of 00:36, 7 November 2014

Check output device is a terminal is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The task is to demonstrate how to check whether the output device is a terminal or not.

See also: Check input device is a terminal

Ada

Works with: GNAT

We use the interface to C library functions isatty() and fileno().

<lang ada>with Ada.Text_IO; use Ada.Text_IO; with Interfaces.C_Streams; use Interfaces.C_Streams;

procedure Test_tty is begin

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

end Test_tty;</lang>

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

C

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

<lang c>#include <unistd.h> // for isatty()

  1. include <stdio.h> // for fileno()

int main() {

   puts(isatty(fileno(stdout))
         ? "stdout is tty"
         : "stdout is not tty");
   return 0;

}</lang>

Output:
$ ./a.out
stdout is tty

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

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

Common Lisp

Works with: SBCL

<lang lisp>(with-open-stream (s *standard-output*)

 (format T "stdout is~:[ not~;~] a terminal~%" 
         (interactive-stream-p s)))</lang>
Output:
$ 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

Crystal

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

Factor

You have to know 1 is the correct file descriptor number: <lang factor> IN: scratchpad USE: unix.ffi IN: scratchpad 1 isatty

--- Data stack: 1 </lang>


Go

<lang go>package main

import (

   "os"
   "fmt"
   "golang.org/x/crypto/ssh/terminal"

)

func main() {

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

}</lang>

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

Javascript/NodeJS

<lang js>node -p -e "Boolean(process.stdout.isTTY)" true</lang>

Nemerle

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). <lang Nemerle>def isTerm = System.Console.IsOutputRedirected;</lang>

OCaml

<lang ocaml>let () =

 print_endline (
   if Unix.isatty Unix.stdout
   then "Output goes to tty."
   else "Output doesn't go to tty."
 )</lang>

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.

Perl

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

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

Perl 6

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'
True
$ perl6 -e 'note $*OUT.t' >/dev/null
False

Racket

<lang racket> (terminal-port? (current-output-port)) </lang>

REXX

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. <lang rexx>/*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 ···   */</lang>

output

output device: terminal

Ruby

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

Rust

<lang rust>/* Rust 0.9 version. Uses C library interface */ extern mod std; use std::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");
   }

}</lang>

Tcl

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: <lang tcl>set toTTY [dict exists [fconfigure stdout] -mode] puts [expr {$toTTY ? "Output goes to tty" : "Output doesn't go to tty"}]</lang> 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.

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. <lang tcl>set toTTY [expr {![catch {fconfigure stdout -mode}]}]</lang>

UNIX Shell

<lang sh>#!/bin/sh

if [ -t 1 ] then

  echo "Output is a terminal"

else

  echo "Output is NOT a terminal" >/dev/tty

fi</lang>