programing

응용 프로그램에서 stdout을 파이프가 아닌 터미널로 생각하도록 속이는 무엇입니까?

showcode 2023. 4. 15. 09:41
반응형

응용 프로그램에서 stdout을 파이프가 아닌 터미널로 생각하도록 속이는 무엇입니까?

"Detect if stdin is terminal or pipe?"와 반대로 하려고 합니다.

STDOUT에서 파이프를 검출하기 때문에 출력 포맷을 변경하는 어플리케이션을 실행하고 있으며 리다이렉트 시 동일한 출력을 얻을 수 있도록 인터랙티브 단말기로 간주하고 싶습니다.

제 생각엔 그걸 싸서expect스크립트 작성 또는 사용proc_open()PHP에서는 가능하지만 그렇지 않습니다.

뭐 좋은 생각 있어?

아하!

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

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

Expect함께 제공되는 unbuffer 스크립트로 이 문제가 해결됩니다.그렇지 않은 경우, 애플리케이션은 TERM 환경 변수가 설정되어 있는 것 등, 출력의 접속처 이외의 것을 참조하고 있을 가능성이 있습니다.

Mac OS X에서는 이전 답변을 참조하여 다음과 같이 "스크립트"를 사용할 수 있습니다.

script -q /dev/null commands...

단, stdout에서 "\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'

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 */
}

사실 그 자체가 PTY를 만든다는 인상을 받았어요.

Linux와 MacOs b 모두에서 a에 대한 @A-Ron의 응답 갱신은 (MacOs 이후) 상태 코드를 간접적으로 전파합니다.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

구체적인 답변에 대해 언급하기엔 너무 새롭지만, 저는 그 질문에 대한 후속 조치를 취하려고 합니다.faketty위의 ingomueller-net이 최근에 저를 도와준 이후 게시한 함수입니다.

이 때문에, 이 모든 것이typescript원하지 않거나 필요 없는 파일을 스크립트 대상 파일로 /dev/null을 추가했습니다.

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

"유닉스 환경의 고급 프로그래밍, Second Edition"의 샘플 코드에는 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 *

나는 달릴 때 색을 얻으려고 했다.shellcheck <file> | lessLinux에서 위의 답변을 시도했지만 텍스트가 있어야 할 위치에서 수평으로 오프셋되는 기묘한 효과가 나타납니다.

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.

(셸 체크에 익숙하지 않은 경우 경고가 표시된 행은 문제가 있는 위치에 맞춰야 합니다).

위의 답변에 대해 셸체크를 사용하기 위해 댓글에서 다음 옵션 중 하나를 사용해 보았습니다.

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에서 작동합니다.

하이라이트를 있는 Ansible output with with with로 출력합니다.tee도 나의 입니다.

export ANSIBLE_FORCE_COLOR=True

언급URL : https://stackoverflow.com/questions/1401002/how-to-trick-an-application-into-thinking-its-stdout-is-a-terminal-not-a-pipe

반응형