[comp.unix.shell] Getting at the first char of a string in Bourne shell

ken@images1.Waterloo.NCR.COM (Ken Braithwaite) (09/28/90)

I am trying to peel off one at a time the letters from a variable
in the Bourne shell, ie from Bourne get B and ourne.
How can I do this?
Thanks in advance.

----------------------------------------------------------------------
Ken Braithwaite            | They couldn't hit an elephant at
                           |   this dist
These opinions are solely  |       last words, General Sedgwick
my own. I don't share.     | 
----------------------------------------------------------------------

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (09/29/90)

In article <1308@ncrwat.Waterloo.NCR.COM> ken@images1.Waterloo.NCR.COM (Ken Braithwaite) writes:
: I am trying to peel off one at a time the letters from a variable
: in the Bourne shell, ie from Bourne get B and ourne.
: How can I do this?

A fairly efficient way would be

    echo "Bourne" | SOMETHING | while read line; do
	...
    done

where SOMETHING is one of

    sed 's/\(.\)/\1\
    /g
    s/\n$//'

    perl -pe 'chop; s/./$&\n/g'

There are lots of other ways.

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

merlyn@iwarp.intel.com (Randal Schwartz) (09/30/90)

In article <9737@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax (Larry Wall) writes:
|     perl -pe 'chop; s/./$&\n/g'
| 
| There are lots of other ways.

Ack.  Just to even out the "do everything in Perl" reputation I've
gotten, here's how to do it *without* Perl.  (And I'm even doing this
as a followup to Larry's article... sheesh.  If that doesn't even out
the score, I don't know what will!)

a="Bourne" # pretend you already have it in $a
first=`expr "$a" : '\(.\).*'` # to get the first char
a=`expr "$a" : '.\(.*\)` # to trim the first char off
echo "$first $a"

[no whitespace in $a, please]

or even:

a="Bourne" # pretend you already have it in $a
eval `echo "$a" | sed 's/\(.\)\(.*\)/first=\1 a="\2"/'`
echo "$first $a"

[This requires well-behaved values of $a... whitespace is OK, quoting
characters are out.]

There.  Not a single 'perl' invocation in the pile :-)

Just another Bourne-shell hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

pim@cti-software.nl (Pim Zandbergen) (09/30/90)

How about 

string=`echo $string | cut -c1`

I don't think the Bourne shell can do this without executing
an external command.

In Korn shell you can use a hack like

string=${string%${string#?}}
-- 
Pim Zandbergen                          domain : pim@cti-software.nl
CTI Software BV                         uucp   : uunet!mcsun!hp4nl!ctisbv!pim
Laan Copes van Cattenburch 70           phone  : +31 70 3542302
2585 GD The Hague, The Netherlands      fax    : +31 70 3512837

mark@hsi.UUCP (Mark Sicignano) (09/30/90)

In article <9737@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax (Larry Wall) writes:
 >     perl -pe 'chop; s/./$&\n/g'
 > 
 > There are lots of other ways.
 >

In article <1990Sep29.193617.25752@iwarp.intel.com> merlyn@iwarp.intel.com (Randal Schwartz) writes:
 >
 >a="Bourne" # pretend you already have it in $a
 >first=`expr "$a" : '\(.\).*'` # to get the first char
 >a=`expr "$a" : '.\(.*\)` # to trim the first char off
 >echo "$first $a"
 >
 >[no whitespace in $a, please]
 >
 >or even:
 >
 >a="Bourne" # pretend you already have it in $a
 >eval `echo "$a" | sed 's/\(.\)\(.*\)/first=\1 a="\2"/'`
 >echo "$first $a"
 >

Double ack!  These ways might work, but what about readability!

echo "Bourne" | awk '
{
	for (i = 0; i < length; i++) {
		print substr($0, i + 1, 1);
	}
}'

Produces:
B
o
u
r
n
e

That's what you want, right?

-mark
-- 
Mark Sicignano                                  ...!uunet!hsi!mark
3M Health Information Systems                   mark@hsi.com
--

scott@tab00.larc.nasa.gov (Scott Yelich) (10/01/90)

>I don't think the Bourne shell can do this without executing
>an external command.

Uh, it CAN be done... the question is whether you want to fork another
process or have a massive hack to accomplish something which is
actually a minimal function (Lets pass a lisp function to get the
first letter to emacs... etc).

As an EXAMPLE only, and an example which YOU can expand...

STRING="STRING"
set +F
case "$STRING" in
  S* ) FIRST=S;;
esac
echo "The first letter of \`\`$STRING'' is \`\`$FIRST\'\'

Now, do you REALLY want to do this?
--
Signature follows. [Skip now]

 -----------------------------------------------------------------------------
 Scott D. Yelich                         scott@[xanth.]cs.odu.edu [128.82.8.1]
 After he pushed me off the cliff, he asked me, as I fell, ``Why'd you jump?''
 Administrator of:    Game-Design requests to <game-design-request@cs.odu.edu>
 ODU/UNIX/BSD/X/C/ROOT/XANTH/CS/VSVN/
 -----------------------------------------------------------------------------

das@oahu.cs.ucla.edu (David Smallberg) (10/02/90)

In article <1990Sep29.215559.25098@cti-software.nl> pim@cti-software.nl (Pim Zandbergen) writes:
>How about 
>In Korn shell you can use a hack like
>
>string=${string%${string#?}}

A fixed-length variable also does the trick:
	typeset -L1 first="$string"
	rest=${string#$first}
Unfortunately, a non- or not clearly documented feature of left- (right-)
justified variables is that leading (trailing) whitespace is stripped off
before the truncating assignment is made, so that
	string="   abc"
	typeset -L1 first="$string"
	echo ">$first<"
yields
	>a<
instead of
	> <
--

-- David Smallberg, das@cs.ucla.edu, ...!{uunet,ucbvax,rutgers}!cs.ucla.edu!das

cevert@airgun.wg.waii.com (C C Evert) (10/02/90)

In article <1308@ncrwat.Waterloo.NCR.COM>, ken@images1.Waterloo.NCR.COM (Ken Braithwaite) writes:
> I am trying to peel off one at a time the letters from a variable
> in the Bourne shell, ie from Bourne get B and ourne.
> How can I do this?
> Thanks in advance.
> 

expr "$SHELL" : '\(.\).*' prints the first letter of SHELL
expr "$SHELL" : '.\(.*\)' prints all but the first letter of SHELL

You still need to check for SHELL being empty.
-- 
C C Evert 
Western Geophysical - A division of Western Atlas International,
A Litton/Dresser Company           DOMAIN addr: cevert@airgun.wg.waii.com
				   UUNET address:  uunet!airgun!cevert

les@chinet.chi.il.us (Leslie Mikesell) (10/02/90)

In article <1990Sep29.215559.25098@cti-software.nl> pim@cti-software.nl (Pim Zandbergen) writes:
>How about 

>string=`echo $string | cut -c1`

>I don't think the Bourne shell can do this without executing
>an external command.

There's always something like:

string=foo
for i in a b c d e f g (you know the rest...)
do
case "$string"
 in
$i*) first=$i
 break
 ;;
esac
done
echo $first

Les Mikesell
  les@chinet.chi.il.us