Detect if stdout is redirected to a pipe (not to a file, character device, terminal, or socket)?

后端 未结 5 892
粉色の甜心
粉色の甜心 2021-02-14 20:50

Ideally, this would be scriptable in shell, but Perl or Python would be fine. C code could be helpful, but probably fails cost/benefit.

I recognize that redirection to a

相关标签:
5条回答
  • 2021-02-14 21:30

    In Python:

    import sys
    print sys.stdout.isatty()
    

    Examples:

    $ ./a
    True
    $ ./a | less
    False
    
    0 讨论(0)
  • 2021-02-14 21:31

    (my comment turned to answer per Alex Dupuy's suggestion) Since you said you can use perl, I guess you can use its -p file test operator (perldoc.perl.org/functions/-X.html); something like perl -e 'exit(-p STDOUT ? 0 : 1);' will tell you if stdout if a pipe or a fifo (without distinguishing between them).

    Fwiw, calling that from the shell is exactly the reason why I used perl -e :)

    0 讨论(0)
  • 2021-02-14 21:33

    The stat command works on MacOS X and (with some finessing of variant implementations) other Linux/Unix variants as well, so it is a solution for me:

    FORMOPT=
    TYPEFORM=
    stat() {
      if [ -z "$FORMOPT" ]; then
        if /usr/bin/stat --version >/dev/null 2>&1; then
          FORMOPT=--format
          TYPEFORM=%F
        else
          FORMOPT=-f
          TYPEFORM=%HT
        fi
      fi
      case $1 in
        type) FORMARG="$FORMOPT $TYPEFORM" ; shift ;;
      esac
      /usr/bin/stat -L $FORMARG "$@"
    }
    
    exec 9>&1
    case `stat type /dev/fd/9` in
      [Ff]ifo*) echo stdout is a pipe ;;
      *) echo stdout is not a pipe ;;
    esac
    
    0 讨论(0)
  • 2021-02-14 21:40

    You could do an fstat to the file descriptor and check returning structure, for example, st_mode = 0x1000 (S_IFIFO) indicates a Named Pipe.

    Example with Python:

    from __future__ import print_function
    import sys
    import os
    
    print(os.fstat(sys.stdout.fileno()), file=sys.stderr)
    

    Output on windows:

    C:> python test_fd.py | more
    nt.stat_result(st_mode=4096, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=0L, st_atime=0L, st_mtime=0L, st_ctime=0L)
    
    C:> python test_fd.py > test_fd.txt
    nt.stat_result(st_mode=33206, st_ino=16888498602769633L, st_dev=0, st_nlink=1, st_uid=0, st_gid=0, st_size=0L, st_atime= 1401119520L, st_mtime=1401119520L, st_ctime=1401119349L)
    
    0 讨论(0)
  • 2021-02-14 21:47

    There is a Linux-specific solution that does what I want:

    exec 9>&1
    case `readlink /dev/fd/9` in
        pipe:\[*\]) echo stdout is a pipe ;;
        *) echo stdout is not a pipe ;;
    esac
    

    but that isn't the answer I am looking for as I want this to run on xBSD as well.

    I've made this answer community wiki, so feel free to improve it, but if you have a non-Linux solution (or a Linux-specific solution using another technique), please create a new answer.

    0 讨论(0)
提交回复
热议问题