1

Is there a way to print or tee one thing to the console and still pass something else through to the next pipe? Something like:

echo dog | printOrWhatnot "PUTTING MY THING DOWN" | sed 's/dog/cat/g' | printOrWhatnot "FLIP IT"|rev

that would result in:

PUTTING MY THING DOWN
FLIP IT
tac

EDIT: This should also work with multiline input:

printOrWhatNot() {...}

seq 10 30 |printOrWhatNot searching for 3s | grep 3

would output

searching for 3s
13
23
30

Lars' answer seemed to only pass along the first input (here it would be 10)

Also ideally the output would come inline during processing which wasn't what I was seeing with Glen's answer. So

seq 10 30 |tee /dev/tty |printOrWhatNot searching for 3s | grep 3

would make for:

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
searching for 3s
13
23
30
3
  • You're aware that all commands in a pipeline run concurrently, right? Nov 5, 2012 at 20:07
  • @Stephane Sure. Well maybe. The consequence here being that the message will be printed every time the function is called?
    – Chris
    Nov 5, 2012 at 20:27
  • No, just that you asking that the text be displayed after the output of tee and before the output of grep suggest that you may think they are run in sequence and not in parallel. Nov 5, 2012 at 21:02

2 Answers 2

2

I'm not aware of any standard command for this purpose, but it's easy enough to craft one of your own in a little shell script. Create the following, make it executable, and add its location to your PATH.

Edit -- updated to handle multi-line standard input, and to handle spaces in the input.

printOrWhatnot:

 #!/bin/bash
 # printOrWhatnot script, to re-pipe stdin, while echoing something else via stderr

 # read stdin (possibly multi-lined) into $my_array[]:
 while read -t 1  piped
 do
    my_array=("${my_array[@]}" "$piped")
 done

 # echo the supplied arguments by sending them to stderr:
 echo "$@" 1>&2

 # now spew $my_array[], line by line, to any further processing:
 arrayLen=${#my_array[@]}
 for (( i=0; i<$arrayLen; i++ ));
 do
    echo ${my_array[$i]}
 done

Now it should work just as you suggested:

 myhost> echo dog | printOrWhatnot "PUTTING MY THING DOWN" | sed 's/dog/cat/g' | printOrWhatnot "FLIP IT"|rev
 PUTTING MY THING DOWN
 FLIP IT
 tac
3
  • Sorry for the comment spam. I think I found out my problem though. I've added another example in the question.
    – Chris
    Nov 5, 2012 at 19:37
  • Well, that does add a layer of complexity. It can still be accomplished with a shell script, by reading into an array -- updating answer. Nov 5, 2012 at 20:21
  • This is pretty much what I ended up going with. I got the same thing for handling spaces by wrapping the array in quotes when its being read. Thanks!
    – Chris
    Nov 6, 2012 at 20:34
2

You need to send your message to a different file descriptor than stdout, and just dump stdin to stdout untouched:

printOrWhatnot() { echo "$@" >&2; cat -; }

If you need your messages to (eventually) appear on stdout, change rev to rev 2>&1 or wrap your pipeline in braces:

{
    echo dog | 
    printOrWhatnot "PUTTING MY THING DOWN" | 
    sed 's/dog/cat/g' | 
    printOrWhatnot "FLIP IT" |
    rev
} 2>&1 
3
  • This method requires that your shell is a Bourne-shell variant (not csh or tcsh for instance), and that stdin isn't empty. But it is nicely compact. Oct 31, 2012 at 1:11
  • @LarsRohrbach, here "echo dog" is doing the job of producing data for stdin. Oct 31, 2012 at 10:55
  • Well of course it is, in this case. I'm just speaking of usage of printOrWhatnot in general. Oct 31, 2012 at 14:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .