Как заставить команду думать, что ее вывод идет на терминал

@meuh относится к команде screen windowlist , которая должна работать для вас при нажатии двух символов control a и " (control / A и двойные кавычки).

Действие, которое показывает номера окон и заголовки окон в двух столбцах, и вы можете нажимать курсор вверх / вниз, чтобы переместиться, чтобы выбрать один. Это та же информация, что и control a w (команда windows , но, возможно, более доступная).

Привязки экрана, которые я вижу (для OSX), используют control a . (control / A и точка) для команды screen dumptermcap . Но любую привязку экрана можно переопределить в вашем .screenrc файл.

55
16.12.2015, 15:39
2 ответа

Основываясь на ответе @Amir , вот сценарий, который генерирует и затем включает библиотеку во время выполнения:

#!/bin/bash
set -euo pipefail

function clean_up {
  trap - EXIT # Restore default handler to avoid recursion
  [[ -e "${isatty_so:-}" ]] && rm "$isatty_so"
}
# shellcheck disable=2154 ## err is referenced but not assigned
trap 'err=$?; clean_up; exit $err' EXIT HUP INT TERM

isatty_so=$(mktemp --tmpdir "$(basename "$0")".XXXXX.isatty.so)
echo "int isatty(int fd) { return 1; }" \
  | gcc -O2 -fpic -shared -ldl -o "$isatty_so" -xc -
# Allow user to SH=/bin/zsh faketty mycommand
"${SH:-$SHELL}" -c 'eval $@' - LD_PRELOAD="$isatty_so" "$@"
0
20.08.2021, 12:16

Неудовлетворенный решениями, представленными здесь до сих пор, я выпустил python. Она была эффективна. Это решение не требует разрешений setuid или каких-либо на самом деле -безумных обезьян -исправлений с общими библиотеками и LD_LIBRARY_PATH. Сохраните этот скрипт где-нибудь в вашем PATH. Не забудьте chmod +xего. Предположим, вы сохранили этот скрипт как pty.

#!/usr/bin/env python

from sys import argv
import os
import signal

# I've had problems with python's File objects at this low a level, so
# we're going to use integers to specify all files in this script.
stdin = 0
stdout = 1
stderr = 2
# Include this if passing the command and arguments to fish to
# prevent fish from applying any expansions.
#import re
#def fish_escape(args):
#    def escape_one(arg):
#        return "'" + re.sub(r"('|\\)", r'\\\1', arg) + "'"
#    escaped_args = map(escape_one, args)
#    return ' '.join(escaped_args)

if len(argv) < 2:
    os.write(stderr,
b"""A tragically beautiful piece of hackery, made to fool programs like ls,
grep, rg, and fd into thinking they're actually connected to a terminal.
Its usage:

pty command [arg1 arg2...]

Examples:
pty ls --color -R | less -r
git log -p | pty rg <search terms> | less -r
""")
    exit(255)

# We do not use forkpty here because it would block ^Cs from reaching the
# child process. And we don't need that.
ptm, pts = os.openpty()
pid = os.fork()
if pid == 0:
    # The child runs this.
    # To get the behaviour we want, we only need to replace the process's
    # stdout with pts. Everything else should remain in place, so that things
    # like `ps -eF | pty rg python | less -r` will still work as intended.
    os.dup2(pts, stdout)
    # This is not like a subprocess.call(). It replaces the entire child
    # process with argv[1:], meaning execvp will not return! Web search
    # "fork exec" for more.
    os.execvp(argv[1], argv[1:])
    # Use this if calling fish.
    #os.execvp('fish', ['fish', '-c', fish_escape(argv[1:])])


# The parent runs this.

# If the parent doesn't close the slave end, the script won't be able to
# exit. The next read on ptm after the child process terminates would hang
# forever because pts would technically still be open.
os.close(pts)

# The whole process group gets SIGINT, including the child, so we don't need
# to react to it. We'll know when to leave, judging by what the child does.
signal.signal(signal.SIGINT, signal.SIG_IGN)

while True:
    try:
        chunk = os.read(ptm, 4096)
    except OSError:
        break
    try:
        os.write(stdout, chunk)
    except BrokenPipeError:
        # This happens when the parent is piping output to another process in a
        # pipeline, like in `pty ls --color -R | less -r`, and the receiving
        # process is terminated before the child has exited. If the receiving
        # process is less, this can happen very easily. It happens every time
        # the user decides to quit less before it has displayed all output. So,
        # we need to stop the child process now.
        os.kill(pid, signal.SIGTERM)
        # Also close the child's inputs and outputs, just in case it is
        # blocking on them and can't react to the SIGTERM as a result.
        os.close(ptm)
        break
wait_pid, status = os.waitpid(pid, 0)
exit(status >> 8)
10
20.08.2021, 12:16

Теги

Похожие вопросы