5

I'd like to pipe data into an interactive command, and have the output of the interactive command be received as input to another command.

For example, I'd like to be able to do something like the following:

echo "Zaphod" | hello.sh | goodbye.sh

and have the output be:

BYE HELLO Zaphod

Here's my initial crack at this, but I'm missing something ;-) I'd actually like the hello.sh to select from a list of things.

hello.sh

echo Please supply your name
read NAME
echo "HELLO $NAME"

goodbye.sh

MSG=$*
if [ -z "$1" ]
then
  MSG=$(cat /dev/stdin)
fi
echo "BYE $MSG"

EDIT: By "select from a list of things", I guess i'm implying my real use case, which is taking anything from stdout, and letting me choose one option, and pass it on to the stdin of something else... For example:

ls /tmp | select_from_list | xargs cat

would allow me to list the files in /tmp/, interactively pick one, then cat the contents of the file.

So my "select_from_list" script actually looks like this:

#!/bin/bash
prompt="Please select an option:"
options=( $* )
if [ -z "$1" ]
then
  options=$(cat /dev/stdin)
fi

PS3="$prompt "
select opt in "${options[@]}" "Quit" ; do 
    if (( REPLY == 1 + ${#options[@]} )) ; then
        exit

    elif (( REPLY > 0 && REPLY <= ${#options[@]} )) ; then
        break

    else
        echo "Invalid option. Try another one."
    fi
done    
echo $opt
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
  • Looks reasonable. Have you tried it? What do you mean by "select from a list of things?" – chepner Dec 11 '15 at 16:50
  • hey! thanks for the feedback... I did try it, and it didn't work. It skips the interactive part - I've added a bit more info about what I mean by "select from a list of things" to my question.... – Brad Parks Dec 11 '15 at 17:18
  • This is really the same question as: http://stackoverflow.com/questions/5843741/how-can-i-pipe-initial-input-into-process-which-will-then-be-interactive – Jeff Y Dec 11 '15 at 17:37
  • @JeffY - I tried that, but it doesnt work - it just hangs for some reason, not showing me the inputs.... `(ls /tmp/ && cat) | select_from_list`. I tried it in both `bash` and `zsh` – Brad Parks Dec 11 '15 at 19:20
  • 1
    stdin of `hello.sh` is connected to the pipe, not the tty. Read from `/dev/tty`, or see http://stackoverflow.com/a/1992967/1944784 for how to exhaust stdin then reopen it for reading. – 4ae1e1 Dec 11 '15 at 20:51

1 Answers1

3

Thanks to 4ae1e1, I figured out how to do what I want - specifically, how to get my select_from_list routine to work:

So now I can do something like this:

ls /tmp/ | select_from_list | xargs cat

to choose a file from /tmp and cat it.

select_from_list

#!/bin/bash
prompt="Please select an item:"

options=()

if [ -z "$1" ]
then
  # Get options from PIPE
  input=$(cat /dev/stdin)
  while read -r line; do
    options+=("$line")
  done <<< "$input"
else
  # Get options from command line
  for var in "$@" 
  do
    options+=("$var") 
  done
fi

# Close stdin
0<&-
# open /dev/tty as stdin
exec 0</dev/tty

PS3="$prompt "
select opt in "${options[@]}" "Quit" ; do 
    if (( REPLY == 1 + ${#options[@]} )) ; then
        exit

    elif (( REPLY > 0 && REPLY <= ${#options[@]} )) ; then
        break

    else
        echo "Invalid option. Try another one."
    fi
done    
echo $opt
Community
  • 1
  • 1
Brad Parks
  • 66,836
  • 64
  • 257
  • 336