简体   繁体   中英

How can I cheat program that stdin is terminal (and not redirected file)?

I am doing standard redirection:

$ cat file.txt | /usr/bin/program

But the program behaves differently if I run it directly in terminal and copy-paste input. It displays a progress bar when the input is a terminal. I would like to have the progress bar anyway.

In short, how can I "cheat" the program that the input comes from the terminal and is not redirected from a file?

It may be simplest to use the expect program; it does most of the necessary work for you.

The necessary work is fiddly. It involves using pseudo-ttys, which are devices that look to programs like terminals. If you're going to roll your own, then the POSIX system calls you need to know about are:

The posix_openpt() interface is relatively new (Issue 6, compared with Issue 4, Version 2 for the other functions listed). If your system doesn't have posix_openpt() , you need to get yourself one of the Unix books (Stevens or Rochkind, probably) to find out how else to do open the master side of a pty, or read your system manuals rather carefully. However, the rationale for posix_openpt() at the link above may also help — it also has guidelines for using the other functions. Linux has posix_openpt() ; so does Mac OS X and by inference the BSD systems generally.

Books:

I assume that the program will call the glibc function isatty() to check whether stdin/stdout is a terminal or not. That's common for programs which use colorized output on terminals or other features of an ANSI terminal like cursor positioning or line erasing / redrawing.

You can trick the program using the LD_PRELOAD environment variable. LD_PRELOAD is handled by the ELF linker and tells that a dynamic library should be loaded before all others. Using this feature it is possible to override library functions, in your case the glibc function isatty() .

Here comes an example:

libisatty.c

/**
 * Overrides the glibc function. Will always return true.
 *
 * Note: Although this should be ok for most applications it can
 * lead to unwanted side effects. It depends on the question
 * why the programm calls isatty()
 */
int isatty(int param) {
    return 1;
}

Makefile

# Make the shared Library
lib: libisatty.c
    gcc -shared -Wl,-soname,libisatty.so.1 -o libisatty.so.1.0  libisatty.c 
    ln -s libisatty.so.1.0 libisatty.so.1
    ln -s libisatty.so.1 libisatty.so

Run:

make lib

It should build fine, I've tested it on Ubuntu12.04 AMD 64.

Now it's time to test the library. :) I've used the command ls --color=auto for tests. ls calls isatty() to decide whether it should colorize it's output or not. If the output is redirected to a file or a pipe it won't be colorized. You can test this easily using the following commands:

ls --color=auto        # should give you colorized output
ls --color=auto | cat  # will give you monochrome output

Now we'll try the second command again using the LD_PRELOAD environment var:

LD_PRELOAD=libisatty.so ls --color=auto | cat

You should see colorized output.

You need to use a pseudo-tty to have the effect you desire. 'man pty' will tell you more about it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM