There are programs which change their output depending on whether their stdout is a tty. So if you put these in a pipeline, or redirect them, the output is different than it would be in your shell. Here is an example:
$ touch a b c
# when running ls alone, it places them on one line
$ ls
a b c
# when stdout is not a tty, it places them on their own line
$ ls > output
$ cat output
a
b
c
output
So, if I want to show someone what a command like this should look like (e.g. I'm writing a tutorial), I have to highlight and copy the output from the terminal and then save it to a file.
It seems like I should be able to do something like this:
ls | ttypipe > output
Where ttypipe
is a hypothetical program whose stdin (and hence ls's stdout) responds with true when asked if it's a tty.
I know that in Ruby, I can do something like this:
require 'pty' # => true
IO.pipe.map(&:tty?) # => [false, false]
PTY.open.map(&:tty?) # => [true, true]
But that's for a child process, and not the current process, so as a result:
$stdin.tty? # => false
I could exec, I can't think of a way to have that affect the stdin file descriptor.
You can't write ttypipe
because a pipe is a pipe, and can never be a tty. However, you can write a ttyexec
with slightly different syntax:
ttyexec ls > output
It would open a pseudo-terminal, run ls
in it, and copy anything ls
writes to the terminal to ttyexec
's stdout.
Lo and behold, there's a tool like this already: script
. It opens a program in a new, hidden pty to log interactions with it, but we can ignore the logging part and just use its terminal opening properties:
$ touch a b c
$ ls
a b c
$ script -q -c 'ls' /dev/null > output
$ cat output
a b c output