6

I know that to capture a pipeline's contents at an intermediate stage of processing, we use tee as ls /bin /usr/bin | sort | uniq | tee abc.txt | grep out , but what if i don't want to redirect the contents after uniq to abc.txt but to screen(through stdout, ofcourse) so that as an end result , i'll have on screen, the intermediate contents after uniq as well as the contents after grep.

  • 1
    The problem is stdout is a pipe to grep out. It's not your terminal anymore. Do you have any sort of guarantee that this will always be run from a terminal? – Joe Sewell Jan 12 '15 at 17:50
  • @JoeSewell In my case, yes from a terminal, but please tell what are the other sources from apart from terminal(are you talking about simply shell-scripting or something else). Just curious. I'm new to Linux and would love to explore what you are talking in detail. – Aman Jan 12 '15 at 17:53
  • One of my comments to an answer below gives a few examples. Running it from within gvim may leave you without a terminal at all. Having this line in a gmake makefile may cause problems if the -j option is used, and the subshell in use doesn't have access to the terminal. cron jobs wouldn't have a terminal, either. A shell script, on the other hand, might have a terminal, unless it's run without one. – Joe Sewell Jan 12 '15 at 17:58
  • @JoeSewell thanks, i'll do some research on them :) – Aman Jan 12 '15 at 18:18
7

sometimes /dev/tty can be used for that...

ls /bin /usr/bin | sort | uniq | tee /dev/tty | grep out | wc
  • 1
    This assumes the command is run from a terminal. – Joe Sewell Jan 12 '15 at 17:48
1

This command worked for me.

ls /bin /usr/bin | sort | uniq | tee /dev/pts/0 | grep out

You could check what is your terminal using the command tty and replace the tee to redirect the output to that terminal.

References

https://stackoverflow.com/a/18025293/1742825

  • That assumes the command runs on the terminal /dev/pts/0. – Joe Sewell Jan 12 '15 at 17:48
  • @JoeSewell, you could see which is the running terminal using tty. I have updated with that information. – Ramesh Jan 12 '15 at 17:49
  • Nice update, but why not use /dev/tty instead? That assumes, of course, that the command even has access to the terminal. If it's run from, for example, inside gvim, there may be no terminal involved at all. Doing this within gmake could become even more complex with multiple jobs, since not all processes can get to "the terminal." – Joe Sewell Jan 12 '15 at 17:53
1

One more option: Use process substitution:

ls /bin /usr/bin | sort | uniq | tee abc.txt >(grep out)

Or, in another form:

ls /bin /usr/bin | sort | uniq | tee abc.txt >(cat) | grep out
1
ls /bin /usr/bin | sort | uniq | tee /dev/fd/2 | grep out | wc

On a linux system you can use the the /dev/fd/[num] links like named pipes in many cases. This will duplicate stdout to stderr, which, typically, is your terminal screen, but doesn't need to be.

  • Only works with bash, not dash /bin/sh on Ubuntu. I use this command for docker build: ID=$(docker build "$dockercontext" 2>&1 | tee /dev/fd/3 - | tail -1) – Daniel Alder Oct 15 '15 at 13:15
  • @DanielAlder - it works fine with dash. but you need to direct it somewhere. where does &3 go? the fd/2 above assumes the command is run from a terminal and &2 goes to the tty. for example: dash -c '{ echo hey; read v; echo "${v#?}" >/dev/fd/2; } <>/dev/fd/1 |:' – mikeserv Oct 16 '15 at 5:24
  • You are right. Didn't realize that /dev/fd/* are now also supported in dash. fd/3 is redirected to stdout in my case. I use this command line now, the other variant was overkill: ID=$(docker build "$1" 2>&1 | tee /dev/fd/2 - | tail -1) – Daniel Alder Oct 16 '15 at 7:51
  • @DanielAlder - those dont really have anything to do with the shell. theyre just files. or... links to file-descriptors anyway. but the shell doesnt put them there or control their behavior at all - those are handled by the kernel. the shell just does open() and dup2() with file-descriptors and it treats those exactly the same as it does any other file. – mikeserv Oct 16 '15 at 7:59
  • You don't know the history, and I didn't know the current situation. Not many years ago, there was no /dev/fd/ in the system. It was compiled directly in bash like /dev/tcp/ too which can be used to open tcp connections. Actually, bash still supports the emulation in case it can't find /dev/fd. Obviously I missed some developments of /proc/self, udev and the kernel so I didn't know that this is now system default. – Daniel Alder Oct 16 '15 at 8:30
0
mkfifo myfifo
cat myfifo& ls /bin /usr/bin | sort | uniq | tee myfifo | grep out

mkfifo creates a FIFO (first in, first out) special file, a.k.a. a named pipe.  Start an asynchronous cat to read from the fifo, and then run your pipeline, teeing the intermediate result to the fifo.

This will produce a [1]+ Done cat myfifo message at the end.  You can suppress that with this magic trick:

(cat myfifo&); ls /bin /usr/bin | sort | uniq | tee myfifo | grep out

For a long term, robust solution, you might want to create a permanent fifo (e.g., $HOME/myfifo) rather than creating a new one every time.  But that will fail if you may be running multiple instances of this simultaneously.  Alternatively,

  • Generate a unique name (e.g., with mktemp).
  • Create the fifo in a directory that's guaranteed to be writable (e.g., /tmp).
  • Remove the fifo at the end of the command.
0

In the case this is being run from a terminal you could

  • start a terminal multiplexer such as tmux or screen
  • split your terminal - in tmux Ctrl B"
  • in the first window touch abc.txt then tail -f abc.txt
  • switch to the second window and run your command. You'll see the file created by tee update.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.