Quote:> In K&P 159p, there is program called pick.
> as a exercise Kernighan and Pike said
> "write new pick program reading in stdin but argumentes"
> that is very difficult for me to write.
> what make this exercise complicated is that there is no way to treat
> input from stdin like input from arguments.
> did anyone solve it?
Here's my current incarnation using ksh93. Enjoy!
--
David Thompson
Foster City, CA
#!/usr/local/bin/ksh
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# $Id: pick,v 1.10 2003/06/01 19:20:20 davidt Exp $
## -- CREDITS
## -- Brian W. Kernighan & Rob Pike, "The Unix Programming Environment"
## -- David Thompson, Jan 1991
# pick loops through each argument on its command line
# and prompts for confirmation. If the command line is
# empty, pick uses stdin, if redirected.
## -- common variables
SCRIPT="${0##*/}"
FASTUSAGE="$SCRIPT [item...]"
USAGE="Name
$SCRIPT - interactive pick list
Usage
$FASTUSAGE
Where
item Each argument is item to accept or reject
Answer 'y' to print the item to stdout
Answer 'n' (or press return) to skip the item
Answer 'a' to auto accept all remaining items
Answer 'q' to skip all remaining items
Options
-version Print version control information
-h/elp Print this help message
Examples
$SCRIPT one two three
rm \`$SCRIPT *\`
awk -F: '{print \$1}' /etc/passwd | $SCRIPT > /tmp/ids
"
## -- timestamp when this file last updated
LAST_REVISION='$Id: pick,v 1.10 2003/06/01 19:20:20 davidt Exp $'
#--------------------------------------------------------------------
# cleanup: delete temporary files upon exit
#--------------------------------------------------------------------
: ${TMPDIR:=/tmp}
trap 'cleanup 4' 1 2 3 15
function cleanup
{
rm -f $TMPDIR/$SCRIPT.$$.*
exit $1
Quote:}
#--------------------------------------------------------------------
# fastusage: print usage error message and exit
#--------------------------------------------------------------------
function fastusage
{
print -u2 "$SCRIPT: Error: $*"
print -u2 "$SCRIPT: Usage: $FASTUSAGE"
print -u2 "$SCRIPT: Try '$SCRIPT -help' for a complete list of options"
exit 1
Quote:}
#--------------------------------------------------------------------
# Process command line arguments
#--------------------------------------------------------------------
## -- loop to process arguments
while [[ $# -ne 0 ]] ; do
case "$1" in
-h|-help) print "$USAGE" ; exit 0 ;;
-version) print "$LAST_REVISION" ; exit 0 ;;
--) shift ; break ;;
-*) fastusage "Unknown option: $1" ;;
*) break ;;
esac
shift
done
## -- nothing to do?
if [[ $# -eq 0 && -t 0 ]] ; then
print "$USAGE"
exit 0
fi
#--------------------------------------------------------------------
# MAIN LOGIC
#--------------------------------------------------------------------
## -- Here we collect our arguments from stdin if none are supplied
## -- on the command line; cat will read stdin until EOF and save to
## -- our temporary file, then we reset the IFS to a newline in order
## -- to preserve spaces in each line of input, then we prep the main
## -- loop by resetting the positional parameters and restoring IFS.
if [[ $# -eq 0 ]] ; then
TMPFILE=$TMPDIR/pick.$$.tmp
cat > $TMPFILE
OLDIFS="$IFS"
IFS='
'
set -- $(<$TMPFILE)
IFS="$OLDIFS"
fi
## -- Using fd 3 & 4 isn't strictly necessary, but this technique
## -- illustrates how we can read & write to the terminal without
## -- actually changing stdin & stdout and without using a subshell.
exec 2> /dev/tty # redirect all stderr to tty
exec 3< /dev/tty # use this for terminal input
exec 4> /dev/tty # use this for terminal output
ANSWER=
if [[ "$ANSWER" != "a" ]] ; then
print -n -u4 "$arg? "
read ANSWER
fi
case "$ANSWER" in
y) print "$arg" ;; # yes
a) print "$arg" ;; # all (auto accept remaining args)
q) break ;; # quit (auto reject remaining args)
esac
done <&3
cleanup 0