" stdin이 터미널인지 파이프인지 감지합니까? " 의 반대를 수행하려고합니다 .
STDOUT에서 파이프를 감지하기 때문에 출력 형식을 변경하는 응용 프로그램을 실행 중이며 리디렉션 할 때 동일한 출력을 얻도록 대화 형 터미널이라고 생각하고 싶습니다.
expect
스크립트로 감싸 거나 proc_open()
PHP에서 사용하면 그렇게 할 것이라고 생각했지만 그렇지 않습니다.
어떤 아이디어가 있습니까?
" stdin이 터미널인지 파이프인지 감지합니까? " 의 반대를 수행하려고합니다 .
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
less -R
터미널 입력이로 이동하는 대화식으로 파이프하려면 파이프를 less -R
추가해야합니다. 예를 들어, 나는 화려한 버전을 원했습니다 git status | less
. -R
색상을 존중하려면 적은 양 으로 전달해야 하며 색상 을 출력하는 데 사용해야 script
합니다 git status
. 그러나 script
키보드의 소유권을 유지 하고 싶지는 않습니다 less
. 그래서 나는 이것을 지금 사용하고 잘 작동합니다 : 0<&- script -qfc "git status" /dev/null | less -R
. 그 첫 몇 문자는이 하나의 명령에 대해 stdin을 닫습니다.
$-
가 "i"에 대한 셸 변수를 보고있는 경우에는 작동하지 않습니다 .
Py_Initialize
적절한 stdin / stderr가 표시되지 않아 항상 충돌이 발생했습니다 .
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
--return
해당 버전이있는 경우이 옵션 을 사용 script
하여 하위 프로세스의 종료 코드를 유지하려고합니다.
function faketty { script -qfc "$(printf "%q " "$@")" /dev/null; }
그렇지 않으면 typescript
많은 경우 명령을 실행할 때마다 이름 이 지정된 파일 이 만들어집니다.
script: illegal option -- f
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를 생성 한다는 인상을 받았습니다 .
이전 답변을 참조하면 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'
a) Linux 및 MacO 모두에서 작동하는 @ A-Ron의 답변 업데이트 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
나는 실행할 때 색상을 얻으려고 노력 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와 함께 사용하려면 주석에서 옵션 중 하나를 시도했습니다.
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에서 작동합니다.
"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 *