[comp.unix.shell] How to convert lower case variable into upper case?

bill@twg.bc.ca (bill) (01/24/91)

I've  got a good one for the gurus.  I have a Bourne script  that
checks  our  modem  lines when there are no modems  available  to
determine who is using which modem and have they been dormant for
any length of time.

I use the /usr/spool/uucp/LCK..ttyi1x lock file (we use Digiboard
and  the ports are ttyi1[a-z,A-Z] to determine which modem  ports
are  in use.  Since the lock file for port P (using modem control
devices)  becomes LCK..ttyi1p (lower case p), my script wants  to
check the access time for /dev/ttyi1p, instead of /dev/ttyi1P.

Is  there any way, when you have something like Port=ttyi1p, that
you  can  map lower case letters in the variable value  to  upper
case?   If it can be done, the next step would be to prevent  the
"i" from getting mapped and only map the last letter (p) to upper
case (P).

My kludge at this stage is:

case $Port in
        i1o)    real_port=i1O;;
        i1p)    real_port=i1P;;
esac

I would love to be able to do something as simple as:

case $Port in
        i1[a-z])        real_port=i1[A-Z];;
esac

but I doubt life would be that kind to me.  Any ideas?
-- 
Bill Irwin    -       The Westrheim Group     -    Vancouver, BC, Canada
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uunet!van-bc!twg!bill     (604) 431-9600 (voice) |     UNIX Systems
bill@twg.bc.ca            (604) 430-4329 (fax)   |     Integration

qpliu@phoenix.princeton.edu (q.p.liu) (01/24/91)

In article <530@twg.bc.ca> bill@twg.bc.ca (bill) writes:
>My kludge at this stage is:

>case $Port in
>        i1o)    real_port=i1O;;
>        i1p)    real_port=i1P;;
>esac

>I would love to be able to do something as simple as:

>case $Port in
>        i1[a-z])        real_port=i1[A-Z];;
>esac

>but I doubt life would be that kind to me.  Any ideas?

If you don't mind lots of processes,

real_port=i1`echo $Port | cut -c3- | tr a-z A-Z`

or maybe,

real_port=`echo $Port | cut -c-2``echo $Port | cut -c3- | tr a-z A-Z`

]) (01/25/91)

How about:

	real_port=`echo "$Port" | sed 's/p$/P/'`

If you *know* that the only character you need to change is a trailing
lowercase-p into a Capital-P, that'll do it.

In fact, if you're walking all of the lock-files and, let's say, you
need to nail two characters, both trailing lowers (p and x) into
Caps (P and X):

	ls /usr/spool/uucp/LCK..tty* 2>/dev/null |
	sed	-e 's/p$/P/' \
		-e 's/x$/X/' |
	while read lockfile
	do
		:	# Whatever
	done

or

	for lockfile in `ls /usr/spool/uucp/LCK..tty* 2>/dev/null |
			sed -e 's/p$/P/' -e 's/x$/X/'`
	do
		:	# process this lockfile
	done

Redirecting stderr to /dev/null on the ls command avoids stderr from
the script when there just happen to be no tty lockfiles.

It wasn't clear to me whether you've got lowercase last characters
and need to switch 'em to Caps or you've got Caps and need to switch
them to lowercase.  Obviously, if you need to go from Caps to lower,
you'll need to reverse the characters in the sed edits I list above.

Here's an extension to make the /dev/tty filename out of the lockfile
name.  I just thought of this...

Assumption:  lockfiles ending in lowercase letters need to be 
converted to last-character-lower to get the ttyname.

	#
	# The sed script does the following:
	#	load the hold space with the lockfile name
	#	delete from ^ through "LCK.."
	#	switch trailing lower-[px] to Cap-[PX]
	#	insert /dev/ to make the device filename
	#	append the lockfile name from the hold space
	#	replace the newline (from G) with a blank
	#
	ls /usr/spool/uucp/LCK..tty* 2>/dev/null |
	sed	-e 'h'			\
		-e 's/.*LCK..//'	\
		-e 's/p$/P/'		\
		-e 's/x$/X/'		\
		-e 's,^,/dev/,'		\
		-e 'G'			\
		-e 's/\n/ /'	|
	while read device lockfile
	do
		:
	done

...Kris
-- 
Kristopher Stephens, | (408-746-6047) | krs@uts.amdahl.com | KC6DFS
Amdahl Corporation   |                |                    |
     [The opinions expressed above are mine, solely, and do not    ]
     [necessarily reflect the opinions or policies of Amdahl Corp. ]

rad@genco.bungi.com (Bob Daniel) (01/26/91)

In article <530@twg.bc.ca> bill@twg.bc.ca (bill) writes:
>Is  there any way, when you have something like Port=ttyi1p, that
>you  can  map lower case letters in the variable value  to  upper
>case?   If it can be done, the next step would be to prevent  the
>"i" from getting mapped and only map the last letter (p) to upper
>case (P).
>
>case $Port in
>        i1[a-z])        real_port=i1[A-Z];;
>esac
>

You can extract the third letter in Port and then pipe it to 'tr [a-z] [A-Z]'
to convert it to upper case.

stuart@amc-gw.amc.com (Stuart Poulin) (01/26/91)

#!/bin/sh

# Here's a couple of fun ways to translate the last char to upper
# case.

# These work for any last character of a-z.

# First, the little used expr. 

Port=i1o
case $Port in
    i1[a-z]) tmp_port=`expr "$Port" : '\(.*\).'`
             Port=$tmp_port`expr "$Port" : '.*\(.\)' | tr 'a-z' 'A-Z' `
        ;;
esac
echo $Port

# Or using associative arrays in awk. (this even works in old awk).
# I seem to do a lot of char translations this way.
#( I used a sh function to simplify the case statement.)

ToUpperLastChar() {
echo $*|
awk  '
BEGIN {
    # build an associate array to do the translation
    split("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z",\
                        low_alpha,",") 

    split("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z",\
                        high_alpha,",")

    for ( i = 1 ; i < 26 ; i++){
        trans[low_alpha[i]] = high_alpha[i]
        trans[high_alpha[i]] = low_alpha[i]
    }       
}


{ 
    StrLen=length($0)
    print substr($0,1,StrLen - 1) trans[substr($0,StrLen)]
}'

}

Port=i1o
case $Port in
     i1[a-z]) Port=`ToUpperLastChar "$Port`
            ;;
esac
echo $Port

bill@twg.bc.ca (Bill Irwin) (01/26/91)

I  asked  for a way to convert the name of a uucp lock file  into
its  upper  case counterpart /dev device name.  Since  you  don't
know  which modem ports might be in use, those solutions that had
a particular letter "wired" in have limited value.

I  received  several  mailed responses.  The  simplest  and  most
easily understandable (by me), provided by Stuart Hood, follows:

case $modem in
        i[1-9][a-z])
        real_modem=i`echo $modem | sed 's/i//' | tr '[a-z]' '[A-Z]'`
        ;;
esac

--
S I E M E N S  Stuart Hood 65-73 Crockhamwell Road, Woodley, Berkshire, UK
-------------  Phone: + 44-734-691994          Email: stuart@siesoft.co.uk
N I X D O R F  The trouble with everyone, is that they generalise too much

I  decided to tune it a little bit because when another Digiboard
is  added, the ports names are "ttyi2x".  I would like the script
to handle all ports regardless of board number.

This  is  clean  and elegant.  You (Net) have probably  saved  me
hours  of  reading about sed in the manual, and I may never  have
stumbled across tr.  Now that I know what these utilities can do,
the  next time I have a similar problem I can research it in  the
manual.

I  think the Net is wonderful for these types of things.   Thanks
to all who responded.
-- 
Bill Irwin    -       The Westrheim Group     -    Vancouver, BC, Canada
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uunet!van-bc!twg!bill     (604) 431-9600 (voice) |     Your Computer  
bill@twg.bc.ca            (604) 430-4329 (fax)   |    Systems Partner

martin@mwtech.UUCP (Martin Weitzel) (01/31/91)

In article <553@twg.bc.ca> bill@twg.bc.ca (Bill Irwin) writes:
>I  asked  for a way to convert the name of a uucp lock file  into
>its  upper  case counterpart /dev device name.  Since  you  don't
>know  which modem ports might be in use, those solutions that had
>a particular letter "wired" in have limited value.
>
>I  received  several  mailed responses.  The  simplest  and  most
>easily understandable (by me), provided by Stuart Hood, follows:
>
>case $modem in
>        i[1-9][a-z])
>        real_modem=i`echo $modem | sed 's/i//' | tr '[a-z]' '[A-Z]'`
>        ;;
>esac

Hmmm, judging from the numerous followups the original questions
seems to draw a lot of answers. As someone else allready metioned
the y-command of sed to simplify the above, I'll turn back from this
and related ways to solve the problem to another "no sub-processes"
solution. Like the original way with "case-in" the following has the
limitation that you must set up all the expected names in advance,
but this time as shell variables, not as case labels:

	i0p=i1P
	i1p=i1P
	i2p=12P
	....etc...

Then use eval 'real_modem='$modem .

Note that setting up the required variables can be also done in a loop:

	for i in 0 1 2 3 4 5 6 ......
	do
		eval 'i'$i'p=i'$1'P
	done

Another idea would be to avoid the variables and do it all in a loop:

	for i in 0 1 2 3 4 5 6 ......
	do
		case $modem in
		i${i}p) real_modem=i${i}P
		esac
	done
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

martin@mwtech.UUCP (Martin Weitzel) (01/31/91)

In article <1075@mwtech.UUCP> martin@mwtech.UUCP I wrote:
>
>	i0p=i1P
>	i1p=i1P
>	i2p=12P
>	....etc...
>
>Then use eval 'real_modem='$modem .
OOPS! Should be ..........=$'$modem of course.
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83