Aha!
The script command does what we want...
script --return --quiet -c "[executable string]" /dev/nullDoes the trick!
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 version16 Comments
If you want to pipe it into something interactive, like less -R, where terminal input goes to less -R, then you need some extra trickery. For example, I wanted a colourful version of git status | less. You need to pass -R to less in order that it respect the colours, and you need to use script to get git status to output colour. But we don't want script to keep ownership of the keyboard, we want this to go to less. So I use this now and it works well: 0<&- script -qfc "git status" /dev/null | less -R . Those first few characters close stdin for this one commmand.
2014-11-26T13:54:10.523Z+00:00
This is amazing. I needed this for an extremely rare use case with an embedded Python library within an executable that is run within Wine. When I ran in a terminal it worked but when I ran the .desktop file I created it would always crash because Py_Initialize didn't see proper stdin/stderr.
2018-09-23T08:50:44.13Z+00:00
Is there an OS agnostic way of doing this? I like the script command on macOS because you don't have to wrap the command in quotes. The script runs and sends output to the tty which is duplicated in the supplied file, but I can't seem to get the linux version to behave the same way... I'm probably doing something wrong. So what's the equivalent linux script command for this on macOS: script -q -t 0 tmp.out perl -e 'print "Test\n"' Test cat tmp.out Test
2018-10-23T14:45:02.747Z+00:00
Based on Chris' solution, I came up with the following little helper function:
faketty() { script -qfc "$(printf "%q " "$@")" /dev/null }The quirky looking printf is necessary to correctly expand the script's arguments in $@ while protecting possibly quoted parts of the command (see example below).
Usage:
faketty <command> <args>Example:
$ 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 True3805 silver badges11 bronze badges
answered Dec 5, 2013 at 13:47
ingomueller.netingomueller.net
4,8053 gold badges38 silver badges34 bronze badges
3 Comments
Referring previous answer, on Mac OS X, "script" can be used like below...
script -q /dev/null commands...But, because it may replace "\n" with "\r\n" on the stdout, you may also need script like this:
script -q /dev/null commands... | perl -pe 's/\r\n/\n/g'If there are some pipe between these commands, you need to flush stdout. for example:
script -q /dev/null commands... | ruby -ne 'print "....\n";STDOUT.flush' | perl -pe 's/\r\n/\n/g'answered Nov 27, 2012 at 15:51
Tsuneo YoshiokaTsuneo Yoshioka
7,9144 gold badges39 silver badges34 bronze badges
I don't know if it's doable from PHP, but if you really need the child process to see a TTY, you can create a PTY.
In 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 */ }I was actually under the impression that expect itself does creates a PTY, though.
7,8002 gold badges16 silver badges43 bronze badges
answered Sep 9, 2009 at 19:21
ephemientephemient
206k39 gold badges292 silver badges402 bronze badges
Updating A-Ron's answer to:
a) work on both Linux & MacOs
b) propagate status code indirectly (since MacOs script does not support it)
Examples:
$ 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: 32,4098 gold badges17 silver badges38 bronze badges
answered Feb 18, 2020 at 11:04
Jonas BerlinJonas Berlin
3,5311 gold badge31 silver badges36 bronze badges
3 Comments
I use a nonstandard SHELL so this function was failing in my (Linux) environment. The script command uses SHELL to run /bin/sh -c ... which runs $cmd. By explicitly setting SHELL=/bin/sh it seems possible to cut out one of those three stages. I replaced the Linux script line with the simpler SHELL=/bin/sh script -qfc "$cmd" /dev/null, and it appears to function identically.
2021-12-16T15:35:37.787Z+00:00
on Mac: Your script doesn't seem to take care of stdin, does it? E.g. uniq doesn't seem to work when it's wrapped in faketty while getting its stdin from a pipe: grep --line-buffered ... | faketty uniq. (I need faketty because I require to pipe uniq's output to yet another command without buffering.)
2023-11-17T06:45:44.743Z+00:00
A followup on the helpful faketty function mentioned in this answer.
I found that this was creating a typescript file that I didn't want/need, so I added /dev/null as the script target file:
function faketty { script -qfc "$(printf "%q " "$@")" /dev/null ; }There's also a pty program included in the sample code of the book "Advanced Programming in the UNIX Environment, Second Edition"!
Here's how to compile pty on Mac OS X:
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 *27.8k7 gold badges51 silver badges93 bronze badges
I was trying to get colors when running shellcheck <file> | less on Linux, so I tried the above answers, but they produce this bizarre effect where text is horizontally offset from where it should be:
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.(For those unfamiliar with shellcheck, the line with the warning is supposed to line up with the where the problem is.)
In order to the answers above to work with shellcheck, I tried one of the options from the comments:
faketty() { 0</dev/null script -qfc "$(printf "%q " "$@")" /dev/null }This works. I also added --return and used long options, to make this command a little less inscrutable:
faketty() { 0</dev/null script --quiet --flush --return --command "$(printf "%q " "$@")" /dev/null }Works in Bash and Zsh.
answered Aug 6, 2019 at 17:14
Nick ODellNick ODell
27.8k7 gold badges51 silver badges93 bronze badges
3 Comments
After failing to get the other approaches working (unbuffer, stdbuf -o0 -e0, script), I implemented a tiny forkpty wrapper along the lines of ephemient's answer, but handling signals, child output, and child exit status: github.com/cyanogilvie/forcetty. (unbuffer actually does work, but pulls in expect which can bring in a lot of dependencies. My little wrapper is just about 100 lines of plain c with no dependencies so it might work better in tiny containers and such).
.png)








