179

「 Detect if stdin is terminal or pipe? 」の反対をやろうとしています。

STDOUT でパイプを検出したために出力形式を変更するアプリケーションを実行していますが、リダイレクト時に同じ出力が得られるように、対話型端末であると認識させたいと考えています。

expectスクリプトでラップするかproc_open()、PHP で a を使用するとうまくいくと思っていましたが、そうではありません。

そこに何かアイデアはありますか?

4

9 に答える 9

188

あはは!

コマンドはscript私たちが望むことを行います...

script --return --quiet -c "[executable string]" /dev/null

トリックを行います!

Usage:
 script [options] [file]

Make a typescript of a terminal session.

Options:
 -a, --append                  append the output
 -c, --command <command>       run command rather than interactive shell
 -e, --return                  return exit code of the child process
 -f, --flush                   run flush after each write
     --force                   use output file even when it is a link
 -q, --quiet                   be quiet
 -t[<file>], --timing[=<file>] output timing data to stderr or to FILE
 -h, --help                    display this help
 -V, --version                 display version
于 2009-09-09T22:06:10.870 に答える
72

Chris のソリューションに基づいて、次の小さなヘルパー関数を思い付きました。

faketty() {
    script -qfc "$(printf "%q " "$@")" /dev/null
}

printfコマンドの引用部分を保護しながら、スクリプトの引数を正しく展開するには、風変わりな外観が必要$@です (以下の例を参照)。

使用法:

faketty <command> <args>

例:

$ python -c "import sys; print sys.stdout.isatty()"
True
$ python -c "import sys; print sys.stdout.isatty()" | cat
False
$ faketty python -c "import sys; print sys.stdout.isatty()" | cat
True
于 2013-12-05T13:47:02.663 に答える
28

Expectに付属する unbuffer スクリプトは、これを問題なく処理する必要があります。そうでない場合、アプリケーションは、出力が接続されているもの以外のものを見ている可能性があります。TERM 環境変数が何に設定されているか。

于 2009-09-11T11:03:51.793 に答える
21

以前の回答を参照すると、Mac OS X では、「スクリプト」は次のように使用できます...

script -q /dev/null commands...

ただし、標準出力で「\n」を「\r\n」に置き換える可能性があるため、次のようなスクリプトも必要になる場合があります。

script -q /dev/null commands... | perl -pe 's/\r\n/\n/g'

これらのコマンド間にパイプがある場合は、stdout をフラッシュする必要があります。例えば:

script -q /dev/null commands... | ruby -ne 'print "....\n";STDOUT.flush' |  perl -pe 's/\r\n/\n/g'
于 2012-11-27T15:51:52.303 に答える
19

PHPから実行できるかどうかはわかりませんが、TTYを確認するために子プロセスが本当に必要な場合は、PTYを作成できます。

C:

#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
#include <unistd.h>
#include <pty.h>

int main(int argc, char **argv) {
    int master;
    struct winsize win = {
        .ws_col = 80, .ws_row = 24,
        .ws_xpixel = 480, .ws_ypixel = 192,
    };
    pid_t child;

    if (argc < 2) {
        printf("Usage: %s cmd [args...]\n", argv[0]);
        exit(EX_USAGE);
    }

    child = forkpty(&master, NULL, NULL, &win);
    if (child == -1) {
        perror("forkpty failed");
        exit(EX_OSERR);
    }
    if (child == 0) {
        execvp(argv[1], argv + 1);
        perror("exec failed");
        exit(EX_OSERR);
    }

    /* now the child is attached to a real pseudo-TTY instead of a pipe,
     * while the parent can use "master" much like a normal pipe */
}

expectしかし、実際にはそれ自体が PTY を作成するという印象を受けました。

于 2009-09-09T19:21:44.620 に答える
3

書籍「UNIX環境での高度なプログラミング 第2版」のサンプルコードにもptyプログラムが含まれています!

Mac OS X で pty をコンパイルする方法は次のとおりです。

man 4 pty  #  pty -- pseudo terminal driver

open http://en.wikipedia.org/wiki/Pseudo_terminal

# Advanced Programming in the UNIX Environment, Second Edition
open http://www.apuebook.com

cd ~/Desktop

curl -L -O http://www.apuebook.com/src.tar.gz

tar -xzf src.tar.gz

cd apue.2e

wkdir="${HOME}/Desktop/apue.2e"

sed -E -i "" "s|^WKDIR=.*|WKDIR=${wkdir}|" ~/Desktop/apue.2e/Make.defines.macos

echo '#undef _POSIX_C_SOURCE' >> ~/Desktop/apue.2e/include/apue.h

str='#include   <sys/select.h>'
printf '%s\n' H 1i "$str" . wq | ed -s calld/loop.c

str='
#undef _POSIX_C_SOURCE
#include <sys/types.h>
'
printf '%s\n' H 1i "$str" . wq | ed -s file/devrdev.c

str='
#include <sys/signal.h>
#include <sys/ioctl.h>
'
printf '%s\n' H 1i "$str" . wq | ed -s termios/winch.c

make

~/Desktop/apue.2e/pty/pty ls -ld *
于 2010-08-05T10:40:33.210 に答える