## ## echo -- Print string with optional construct expansion ## Copyright (c) 1998-2008 Ralf S. Engelschall ## ## This file is part of shtool and free software; you can redistribute ## it and/or modify it under the terms of the GNU General Public ## License as published by the Free Software Foundation; either version ## 2 of the License, or (at your option) any later version. ## ## This file is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ## USA, or contact Ralf S. Engelschall . ## str_tool="echo" str_usage="[-n|--newline] [-e|--expand] [ ...]" arg_spec="0+" opt_spec="n.e." opt_alias="n:newline,e:expand" opt_n=no opt_e=no . ./sh.common text="$*" # check for broken escape sequence expansion seo='' bytes=`echo '\1' | wc -c | awk '{ printf("%s", $1); }'` if [ ".$bytes" != .3 ]; then bytes=`echo -E '\1' | wc -c | awk '{ printf("%s", $1); }'` if [ ".$bytes" = .3 ]; then seo='-E' fi fi # check for existing -n option (to suppress newline) minusn='' bytes=`echo -n 123 2>/dev/null | wc -c | awk '{ printf("%s", $1); }'` if [ ".$bytes" = .3 ]; then minusn='-n' fi # determine terminal bold sequence term_bold='' term_norm='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[Bb]'`" != . ]; then case $TERM in # for the most important terminal types we directly know the sequences xterm|xterm*|vt220|vt220*) term_bold=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' /dev/null` term_norm=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' /dev/null` ;; vt100|vt100*|cygwin) term_bold=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' /dev/null` term_norm=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' /dev/null` ;; # for all others, we try to use a possibly existing `tput' or `tcout' utility * ) paths=`echo $PATH | sed -e 's/:/ /g'` for tool in tput tcout; do for dir in $paths; do if [ -r "$dir/$tool" ]; then for seq in bold md smso; do # 'smso' is last bold="`$dir/$tool $seq 2>/dev/null`" if [ ".$bold" != . ]; then term_bold="$bold" break fi done if [ ".$term_bold" != . ]; then for seq in sgr0 me rmso init reset; do # 'reset' is last norm="`$dir/$tool $seq 2>/dev/null`" if [ ".$norm" != . ]; then term_norm="$norm" break fi done fi break fi done if [ ".$term_bold" != . ] && [ ".$term_norm" != . ]; then break; fi done ;; esac if [ ".$term_bold" = . ] || [ ".$term_norm" = . ]; then echo "$msgprefix:Warning: unable to determine terminal sequence for bold mode" 1>&2 term_bold='' term_norm='' fi fi # determine user name username='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[uUgG]'`" != . ]; then username="`(id -un) 2>/dev/null`" if [ ".$username" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then username=`echo $str | sed -e 's/^uid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` fi if [ ".$username" = . ]; then username="$LOGNAME" if [ ".$username" = . ]; then username="$USER" if [ ".$username" = . ]; then username="`(whoami) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$username" = . ]; then username="`(who am i) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$username" = . ]; then username='unknown' fi fi fi fi fi fi fi # determine user id userid='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%U'`" != . ]; then userid="`(id -u) 2>/dev/null`" if [ ".$userid" = . ]; then userid="`(id -u ${username}) 2>/dev/null`" if [ ".$userid" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then userid=`echo $str | sed -e 's/^uid[ ]*=[ ]*//' -e 's/(.*$//'` fi if [ ".$userid" = . ]; then userid=`(getent passwd ${username}) 2>/dev/null | \ sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \ sed -e 'q' | sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \ sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$userid" = . ]; then userid='?' fi fi fi fi fi fi fi fi # determine (primary) group id groupid='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[gG]'`" != . ]; then groupid="`(id -g ${username}) 2>/dev/null`" if [ ".$groupid" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then groupid=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*//' -e 's/(.*$//'` fi if [ ".$groupid" = . ]; then groupid=`(getent passwd ${username}) 2>/dev/null | \ sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \ sed -e 'q' | sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \ sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` if [ ".$groupid" = . ]; then groupid='?' fi fi fi fi fi fi fi # determine (primary) group name groupname='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%g'`" != . ]; then groupname="`(id -gn ${username}) 2>/dev/null`" if [ ".$groupname" = . ]; then str="`(id) 2>/dev/null`" if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then groupname=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` fi if [ ".$groupname" = . ]; then groupname=`(getent group) 2>/dev/null | \ grep "^[^:]*:[^:]*:${groupid}:" | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname=`grep "^[^:]*:[^:]*:${groupid}:" /etc/group 2>/dev/null | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname=`(ypcat group; niscat group) 2>/dev/null | \ sed -e 'q' | grep "^[^:]*:[^:]*:${groupid}:" | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname=`(nidump group .) 2>/dev/null | \ grep "^[^:]*:[^:]*:${groupid}:" | \ sed -e 's/:.*$//'` if [ ".$groupname" = . ]; then groupname='?' fi fi fi fi fi fi fi # determine host and domain name hostname='' domainname='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%h'`" != . ]; then hostname="`(uname -n) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$hostname" = . ]; then hostname="`(hostname) 2>/dev/null |\ awk '{ printf("%s", $1); }'`" if [ ".$hostname" = . ]; then hostname='unknown' fi fi case $hostname in *.* ) domainname=".`echo $hostname | cut -d. -f2-`" hostname="`echo $hostname | cut -d. -f1`" ;; esac fi if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%d'`" != . ]; then if [ ".$domainname" = . ]; then if [ -f /etc/resolv.conf ]; then domainname="`grep '^[ ]*domain' /etc/resolv.conf | sed -e 'q' |\ sed -e 's/.*domain//' \ -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ -e 's/^\.//' -e 's/^/./' |\ awk '{ printf("%s", $1); }'`" if [ ".$domainname" = . ]; then domainname="`grep '^[ ]*search' /etc/resolv.conf | sed -e 'q' |\ sed -e 's/.*search//' \ -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ -e 's/ .*//' -e 's/ .*//' \ -e 's/^\.//' -e 's/^/./' |\ awk '{ printf("%s", $1); }'`" fi fi fi fi # determine current time time_day='' time_month='' time_year='' time_monthname='' if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[DMYm]'`" != . ]; then time_day=`date '+%d'` time_month=`date '+%m'` time_year=`date '+%Y' 2>/dev/null` if [ ".$time_year" = . ]; then time_year=`date '+%y'` case $time_year in [5-9][0-9]) time_year="19$time_year" ;; [0-4][0-9]) time_year="20$time_year" ;; esac fi case $time_month in 1|01) time_monthname='Jan' ;; 2|02) time_monthname='Feb' ;; 3|03) time_monthname='Mar' ;; 4|04) time_monthname='Apr' ;; 5|05) time_monthname='May' ;; 6|06) time_monthname='Jun' ;; 7|07) time_monthname='Jul' ;; 8|08) time_monthname='Aug' ;; 9|09) time_monthname='Sep' ;; 10) time_monthname='Oct' ;; 11) time_monthname='Nov' ;; 12) time_monthname='Dec' ;; esac fi # expand special ``%x'' constructs if [ ".$opt_e" = .yes ]; then text=`echo $seo "$text" |\ sed -e "s/%B/${term_bold}/g" \ -e "s/%b/${term_norm}/g" \ -e "s/%u/${username}/g" \ -e "s/%U/${userid}/g" \ -e "s/%g/${groupname}/g" \ -e "s/%G/${groupid}/g" \ -e "s/%h/${hostname}/g" \ -e "s/%d/${domainname}/g" \ -e "s/%D/${time_day}/g" \ -e "s/%M/${time_month}/g" \ -e "s/%Y/${time_year}/g" \ -e "s/%m/${time_monthname}/g" 2>/dev/null` fi # create output if [ .$opt_n = .no ]; then echo $seo "$text" else # the harder part: echo -n is best, because # awk may complain about some \xx sequences. if [ ".$minusn" != . ]; then echo $seo $minusn "$text" else echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text" fi fi shtool_exit 0 ## ## manual page ## =pod =head1 NAME B - B echo(1) extensional command =head1 SYNOPSIS B [B<-n>|B<--newline>] [B<-e>|B<--expand>] I =head1 DESCRIPTION B is an echo(1) style command which prints I to F and optionally provides special expansion constructs (terminal bold mode, environment details, date, etc) and newline control. The trick of this command is that it provides a portable B<-n> option and hides the gory details needed to find out the environment details under option B<-e>. =head1 OPTIONS The following command line options are available. =over 4 =item B<-n>, B<--newline> By default, output is written to F followed by a "newline" (ASCII character 0x0a). If option B<-n> is used, this newline character is omitted. =item B<-e>, B<--expand> If option B<-e> is used, I can contain special "B<%>I" constructs which are expanded before the output is written. Currently the following constructs are recognized: =over 4 =item B<%B> switch terminal mode to bold display mode. =item B<%b> switch terminal mode back to normal display mode. =item B<%u> the current user name. =item B<%U> the current user id (numerical). =item B<%g> the current group name. =item B<%G> the current group id (numerical). =item B<%h> the current hostname (without any domain extension). =item B<%d> the current domain name. =item B<%D> the current day of the month. =item B<%M> the current month (numerical). =item B<%m> the current month name. =item B<%Y> the current year. =back =back =head1 EXAMPLE # shell script shtool echo -n -e "Enter your name [%B%u%b]: "; read name shtool echo -e "Your Email address might be %u@%h%d" shtool echo -e "The current date is %D-%m-%Y" =head1 HISTORY The B B command was originally written by Ralf S. Engelschall Erse@engelschall.comE in 1998 for I (WML) under the name B. It was later taken over into B. =head1 SEE ALSO shtool(1), echo(1). =cut