欺骗应用程序认为它的标准输出是一个终端,而不是管道

时间:2009-09-09 17:31:55

标签: bash terminal pipe stdin

我正在尝试与

相反

Detect if stdin is a terminal or pipe?

我正在运行一个正在更改其输出格式的应用程序,因为它检测到stdout上的管道,我希望它认为它是一个交互式终端,以便在重定向时获得相同的输出。

我当时认为将它包装在expect脚本中或在PHP中使用proc_open()就可以了,但事实并非如此。

有任何想法吗?

9 个答案:

答案 0 :(得分:162)

啊哈!

script命令执行我们想要的操作......

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

诀窍!

答案 1 :(得分:55)

基于Chris' solution,我提出了以下小辅助功能:

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

答案 2 :(得分:20)

unbuffer 附带的Expect脚本应处理此问题。如果不是,则应用程序可能正在查看其输出所连接的内容之外的其他内容,例如。 TERM环境变量设置为什么。

答案 3 :(得分:16)

我不知道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。

答案 4 :(得分:14)

参考上一个答案,在Mac OS X上,&#34;脚本&#34;可以像下面这样使用......

script -q /dev/null commands...

但是,因为它可能会改变&#34; \ n&#34;到&#34; \ r \ n&#34;,我需要像这样跑。

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'

答案 5 :(得分:7)

对特定答案的评论太新了,但我想我会跟进ingomueller-net发布的faketty函数,因为它最近帮助了我。

我发现这是创建一个我不想要/不需要的typescript文件所以我添加了/ dev / null作为脚本目标文件:

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

答案 6 :(得分:6)

更新@ A-Ron的答案 a)在Linux和MacO上均可工作 b)间接传播状态代码(因为MacO script不支持)

faketty () {
  # Create a temporary file for storing the status code
  tmp=$(mktemp)

  # Ensure it worked or fail with status 99
  [ "$tmp" ] || return 99

  # Produce a script that runs the command provided to faketty as
  # arguments and stores the status code in the temporary file
  cmd="$(printf '%q ' "$@")"'; echo $? > '$tmp

  # Run the script through /bin/sh with fake tty
  if [ "$(uname)" = "Darwin" ]; then
    # MacOS
    script -Fq /dev/null /bin/sh -c "$cmd"
  else
    script -qfc "/bin/sh -c $(printf "%q " "$cmd")" /dev/null
  fi

  # Ensure that the status code was written to the temporary file or
  # fail with status 99
  [ -s $tmp ] || return 99

  # Collect the status code from the temporary file
  err=$(cat $tmp)

  # Remove the temporary file
  rm -f $tmp

  # Return the status code
  return $err
}

示例:

$ faketty false ; echo $?
1

$ faketty echo '$HOME' ; echo $?
$HOME
0

embedded_example () {
  faketty perl -e 'sleep(5); print "Hello  world\n"; exit(3);' > LOGFILE 2>&1 </dev/null &
  pid=$!

  # do something else
  echo 0..
  sleep 2
  echo 2..

  echo wait
  wait $pid
  status=$?
  cat LOGFILE
  echo Exit status: $status
}

$ embedded_example
0..
2..
wait
Hello  world
Exit status: 3

答案 7 :(得分:1)

我试图在运行shellcheck <file> | less时获得颜色,所以我尝试了上面的答案,但是它们在文本水平偏移其应有的位置时会产生这种奇怪的效果:

In ./all/update.sh line 6:
                          for repo in $(cat repos); do
                                                                  ^-- SC2013: To read lines rather than words, pipe/redirect to a 'while read' loop.

(对于那些不熟悉shellcheck的人,应该将带有警告的行与问题所在的位置对齐。)

为了使以上答案能与shellcheck配合使用,我尝试了以下注释中的一个选项:

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

这有效。我还添加了--return并使用了较长的选项,以使此命令变得难以理解:

faketty() {                       
    0</dev/null script --quiet --flush --return --command "$(printf "%q " "$@")" /dev/null
}

在Bash和Zsh中工作。

答案 8 :(得分:0)

“UNIX环境中的高级编程,第二版”一书的示例代码中还包含一个pty程序!

以下是在Mac OS X上编译pty的方法:

http://codesnippets.joyent.com/posts/show/8786