Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is there a "successor" operator in bash?

62 views
Skip to first unread message

Alan Mackenzie

unread,
Sep 17, 2016, 11:36:24 AM9/17/16
to
By a "successor" operator I mean something that will give me the next
ASCII value when applied to a variable whose value is an ASCII character.

So if I do

LETTER=Q

I would like an operator "succ" such that when I do

LETTER=succ $LETTER
echo $LETTER

, I would see R displayed.

If there isn't such an operator available, how would I best program
something in bash to do the job?

TIA.

--
Alan Mackenzie (Nuremberg, Germany).

Janis Papanagnou

unread,
Sep 17, 2016, 12:29:17 PM9/17/16
to
On 17.09.2016 17:36, Alan Mackenzie wrote:
> By a "successor" operator I mean something that will give me the next
> ASCII value when applied to a variable whose value is an ASCII character.
>
> So if I do
>
> LETTER=Q
>
> I would like an operator "succ" such that when I do
>
> LETTER=succ $LETTER
> echo $LETTER
>
> , I would see R displayed.
>
> If there isn't such an operator available, how would I best program
> something in bash to do the job?

I don't know of such an operator. (I needed that function a couple years
ago and implemented it as a builtin in ksh, which had the advantage that
it is much faster than triggering an external process every time you need
one successor character. But you wanted someting in bash...) - I came up
with this possibility which should be fairly fast after the setup...

# setup: create once a string of printable ASCII characters (#32..#126)
ch=$( printf "%dP" $( seq 32 126 ) | dc )

LETTER=Q

# strip characters until the desired character, and print the next one
m=${ch##*"${LETTER}"} ; printf "%c\n" "${m:0:1}"


You can of course hide that code in a function and call it by a name.

Janis

>
> TIA.
>

Janis Papanagnou

unread,
Sep 17, 2016, 12:42:21 PM9/17/16
to
Two more comments on the code...

1. printf's %c seems to print anyway only the first character of the string,
so it could be reduced to

m=${ch##*"${LETTER}"} ; printf "%c\n" "${m}"

which is now even POSIX standard.

2. In the setup code you can use more shell builtins, less external processes

ch=$( printf "%dP" $( echo {32..126} ) | dc )

which makes it non-standard, though, but you get a faster setup in bash.

Janis Papanagnou

unread,
Sep 17, 2016, 1:05:49 PM9/17/16
to
On 17.09.2016 17:36, Alan Mackenzie wrote:
> By a "successor" operator I mean something that will give me the next
> ASCII value when applied to a variable whose value is an ASCII character.
>
> So if I do
>
> LETTER=Q
>
> I would like an operator "succ" such that when I do
>
> LETTER=succ $LETTER
> echo $LETTER
>
> , I would see R displayed.
>
> If there isn't such an operator available, how would I best program
> something in bash to do the job?

If one thinks more about a problem many more options come to mind...

This one is using yet another printf feature to create the numeric ASCII
value (which seems to work in bash, ksh, zsh, but I don't know whether
it's POSIX standard)...

LETTER=Q
echo $(( $( printf "%d\n" "'$LETTER" ) + 1 ))P | dc


No setup required, but one external process (dc) per invocation.

Take your pick.

Janis

>
> TIA.
>

Kaz Kylheku

unread,
Sep 17, 2016, 2:07:24 PM9/17/16
to
On 2016-09-17, Alan Mackenzie <a...@muc.de> wrote:
> By a "successor" operator I mean something that will give me the next
> ASCII value when applied to a variable whose value is an ASCII character.
>
> So if I do
>
> LETTER=Q
>
> I would like an operator "succ" such that when I do
>
> LETTER=succ $LETTER
> echo $LETTER

$ txr -p '(succ #\A)'
#\B

$ txr -P '(succ (get-char))'
A
B

Ed Morton

unread,
Sep 17, 2016, 2:12:42 PM9/17/16
to
Why? If you are doing something like this then it's probably in the context of
manipulating text and bash is not a tool for manipulating text, it's an
environment from which to call tools with a language to sequence those calls.

The standard UNIX tool for general purpose text manipulation is awk and you can
do this with GNU awk as:

$ awk -l ordchr 'BEGIN{print chr(ord("Q")+1)}'
R

within the context of whatever other text manipulation you are doing.

Ed.

Kaz Kylheku

unread,
Sep 17, 2016, 2:22:36 PM9/17/16
to
On 2016-09-17, Ed Morton <morto...@gmail.com> wrote:
> The standard UNIX tool for general purpose text manipulation is awk

... which *cannot* actually do the following, so I'm bringing up that
standard tool just for giggles; however, ...

Kaz Kylheku

unread,
Sep 17, 2016, 2:44:00 PM9/17/16
to
On 2016-09-17, Alan Mackenzie <a...@muc.de> wrote:
> By a "successor" operator I mean something that will give me the next
> ASCII value when applied to a variable whose value is an ASCII character.
>
> So if I do
>
> LETTER=Q
>
> I would like an operator "succ" such that when I do
>
> LETTER=succ $LETTER
> echo $LETTER
>
> , I would see R displayed.

If you can constrain your problem to, say, characters in a certain
range (you don't need the successor of {, ~ or 漢) then you may be
able to get away with the tr utility.

For instance, upper case ROT13: successor modulo the alphabet ring:

$ echo "ABCZ" | tr '[A-Z]' '[B-ZA]'
BCDA

tr here maps A to B, B to C and so on. Then Z is arbitrarily mapped to
A, which is easily changed to whatever you want.

Kaz Kylheku

unread,
Sep 17, 2016, 2:49:08 PM9/17/16
to
On 2016-09-17, Kaz Kylheku <221-50...@kylheku.com> wrote:
> On 2016-09-17, Alan Mackenzie <a...@muc.de> wrote:
>> By a "successor" operator I mean something that will give me the next
>> ASCII value when applied to a variable whose value is an ASCII character.
>>
>> So if I do
>>
>> LETTER=Q
>>
>> I would like an operator "succ" such that when I do
>>
>> LETTER=succ $LETTER
>> echo $LETTER
>>
>> , I would see R displayed.
>
> If you can constrain your problem to, say, characters in a certain
> range (you don't need the successor of {, ~ or 漢) then you may be
> able to get away with the tr utility.
>
> For instance, upper case ROT13: successor modulo the alphabet ring:
>
> $ echo "ABCZ" | tr '[A-Z]' '[B-ZA]'
> BCDA

I didn't mean to imply that you can't handle { or ~; of course we
can rotate the entire ASCII range, for instance:

$ echo "ABCZ" | tr '[\000-\177]' '[\001-\177\000]'
BCD[
$

Z went to [, and the LF went to VT (vertical tab).

I just meant that if you have a certain set of characters in mind, you
can just deal with those.

Ed Morton

unread,
Sep 17, 2016, 3:22:24 PM9/17/16
to
On 9/17/2016 1:22 PM, Kaz Kylheku wrote:
> On 2016-09-17, Ed Morton <morto...@gmail.com> wrote:
>> The standard UNIX tool for general purpose text manipulation is awk
>
> ... which *cannot* actually do the following, so I'm bringing up that
> standard tool just for giggles; however, ...

Sure it can, see below. I didn't say "POSIX standard".

Kaz Kylheku

unread,
Sep 17, 2016, 3:44:43 PM9/17/16
to
On 2016-09-17, Ed Morton <morto...@gmail.com> wrote:
> On 9/17/2016 1:22 PM, Kaz Kylheku wrote:
>> On 2016-09-17, Ed Morton <morto...@gmail.com> wrote:
>>> The standard UNIX tool for general purpose text manipulation is awk
>>
>> ... which *cannot* actually do the following, so I'm bringing up that
>> standard tool just for giggles; however, ...
>
> Sure it can, see below. I didn't say "POSIX standard".

You said "UNIX Standard" which is the same thing. The Single Unix
Specification is identical to IEEE 1003.1 ("POSIX").

>>> you can do this with GNU awk as:

I.e. GNU Is Not Unix Awk.

Ed Morton

unread,
Sep 17, 2016, 7:13:21 PM9/17/16
to
On 9/17/2016 2:44 PM, Kaz Kylheku wrote:
> On 2016-09-17, Ed Morton <morto...@gmail.com> wrote:
>> On 9/17/2016 1:22 PM, Kaz Kylheku wrote:
>>> On 2016-09-17, Ed Morton <morto...@gmail.com> wrote:
>>>> The standard UNIX tool for general purpose text manipulation is awk
>>>
>>> ... which *cannot* actually do the following, so I'm bringing up that
>>> standard tool just for giggles; however, ...
>>
>> Sure it can, see below. I didn't say "POSIX standard".
>
> You said "UNIX Standard" which is the same thing.

No, I did not. Reread the text you quoted. Or don't. Whatever...

Chris F.A. Johnson

unread,
Sep 17, 2016, 11:08:08 PM9/17/16
to
On 2016-09-17, Alan Mackenzie wrote:
> By a "successor" operator I mean something that will give me the next
> ASCII value when applied to a variable whose value is an ASCII character.
>
> So if I do
>
> LETTER=Q
>
> I would like an operator "succ" such that when I do
>
> LETTER=succ $LETTER
> echo $LETTER
>
> , I would see R displayed.
>
> If there isn't such an operator available, how would I best program
> something in bash to do the job?

succ()
{
local chr=$1
local str=${2:-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890}
local lft=${str%%"$chr"*}
printf "%c\n" "${str#$lft?}"
}


--
Chris F.A. Johnson

Rakesh Sharma

unread,
Sep 19, 2016, 3:33:20 AM9/19/16
to
ord() {
printf '%d\n' "'$1"
}

chr() {
dc -e "$1P"
}

succ() {
chr "$(dc -e "$(ord "$1") 1 + p")"
}

# stub
l=Q
l=$(succ "$l")
echo "$l"

Alan Mackenzie

unread,
Sep 19, 2016, 4:09:36 AM9/19/16
to
Hello, Ed

Ed Morton <morto...@gmail.com> wrote:
> On 9/17/2016 10:36 AM, Alan Mackenzie wrote:
>> By a "successor" operator I mean something that will give me the next
>> ASCII value when applied to a variable whose value is an ASCII character.
>>
>> So if I do
>>
>> LETTER=Q
>>
>> I would like an operator "succ" such that when I do
>>
>> LETTER=succ $LETTER
>> echo $LETTER
>>
>> , I would see R displayed.
>>
>> If there isn't such an operator available, how would I best program
>> something in bash to do the job?
>>
>> TIA.
>>

> Why? If you are doing something like this then it's probably in the
> context of manipulating text and bash is not a tool for manipulating
> text, it's an environment from which to call tools with a language to
> sequence those calls.

Having applied a mercurial tag to my repository, I sometimes want to
apply the "next" tag as well. This involves incrementing a character in
the tag name.

> The standard UNIX tool for general purpose text manipulation is awk
> ....

AWK would seem to be overkill for something so simple.

> .... and you can do this with GNU awk as:

> $ awk -l ordchr 'BEGIN{print chr(ord("Q")+1)}'
> R

> within the context of whatever other text manipulation you are doing.

In the end, I just used

echo ch | tr 'ABCDEFGHIJKLMNOPQRSTUVWXY' 'BCDEFGHIJKLMNOPQRSTUVWXYZ'

, which more than covers the range I'll need. It feels awkward, and
there ought to be something better, but it seems there is not.

> Ed.

Alan Mackenzie

unread,
Sep 19, 2016, 4:14:28 AM9/19/16
to
Hello, Kaz.
Thanks, this is what I have ended up doing (with error handling if the
letter was originally Z).

It seems strange that something so simple needs such an awkward
contrivance.

Kenny McCormack

unread,
Sep 19, 2016, 5:06:06 AM9/19/16
to
In article <nro6fs$2d4t$1...@colin.muc.de>, Alan Mackenzie <a...@muc.de> wrote:
>Ed Morton <morto...@gmail.com> wrote:
>> Why? If you are doing something like this then it's probably in the
>> context of manipulating text and bash is not a tool for manipulating
>> text, it's an environment from which to call tools with a language to
>> sequence those calls.
...
>> The standard UNIX tool for general purpose text manipulation is awk
...
>AWK would seem to be overkill for something so simple.
>
>> .... and you can do this with GNU awk as:
>
>> $ awk -l ordchr 'BEGIN{print chr(ord("Q")+1)}'
>> R
>
>> within the context of whatever other text manipulation you are doing.
>
>In the end, I just used
>
> echo ch | tr 'ABCDEFGHIJKLMNOPQRSTUVWXY' 'BCDEFGHIJKLMNOPQRSTUVWXYZ'
>
>, which more than covers the range I'll need. It feels awkward, and
>there ought to be something better, but it seems there is not.

Well, there is. Ed has already shown you the way. But you seem intent on
doing it in bash, which is, I suppose, on-topic for this particular
newsgroup. This newsgroup seems to attract a lot of "shell-only"
solutions, on the general theme of "Yes! See? If I just push hard enough,
I *can* smash this square peg into that round hole."

There is often a tradeoff between "portability" (i.e., not depending on
any/all of "awk", "gawk" or "gawk with the ordchr extension library
available") and elegance/beauty. In most cases like this, AWK is *not*
"overkill".

>It seems strange that something so simple needs such an awkward
>contrivance.

See above.

Note that if you're willing to assume bash (as seems to be the case), you
can do:

tr 'ABCDEFGHIJKLMNOPQRSTUVWXY' 'BCDEFGHIJKLMNOPQRSTUVWXYZ' <<< $ch

--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain in
compliance with said RFCs, the actual sig can be found at the following web address:
http://www.xmission.com/~gazelle/Sigs/Voltaire

Brian Patrie

unread,
Sep 19, 2016, 5:35:53 AM9/19/16
to
On 2016-09-17 13:43, Kaz Kylheku wrote:
> If you can constrain your problem to, say, characters in a certain
> range (you don't need the successor of {, ~ or 漢) then you may be
> able to get away with the tr utility.
>
> For instance, upper case ROT13: successor modulo the alphabet ring:
>
> $ echo "ABCZ" | tr '[A-Z]' '[B-ZA]'
> BCDA
>
> tr here maps A to B, B to C and so on. Then Z is arbitrarily mapped to
> A, which is easily changed to whatever you want.

Ah, the ever-popular slip of confusing tr(1) syntax with globbing.
The [ ] are superfluous (and merely get translated to themselves).

Ed Morton

unread,
Sep 19, 2016, 10:28:56 AM9/19/16
to
In what way is it overkill? It's just another UNIX tool you can call to do a
job, just like you're using tr now, BUT it'll work for all characters and
doesn't require you to hard-code them.

>
>> .... and you can do this with GNU awk as:
>
>> $ awk -l ordchr 'BEGIN{print chr(ord("Q")+1)}'
>> R
>
>> within the context of whatever other text manipulation you are doing.
>
> In the end, I just used
>
> echo ch | tr 'ABCDEFGHIJKLMNOPQRSTUVWXY' 'BCDEFGHIJKLMNOPQRSTUVWXYZ'

You asked for a solution to give you the next ascii character given an ascii
character, not "the next upper case letter given an upper case letter excluding Z".

>
> , which more than covers the range I'll need. It feels awkward, and
> there ought to be something better, but it seems there is not.

The awk solution is better. If you feel it's lengthy and you do want to call it
from your shell, put it in a shell function:

$ succ() { awk -v c="$1" -l ordchr 'BEGIN{print chr(ord(c)+1)}'; }
$ succ C
D

Regards,

Ed

Christian Weisgerber

unread,
Sep 19, 2016, 11:30:08 AM9/19/16
to
On 2016-09-19, Brian Patrie <bpa...@bellsouth.spamisicky.net> wrote:

> Ah, the ever-popular slip of confusing tr(1) syntax with globbing.
> The [ ] are superfluous (and merely get translated to themselves).

Well, the 4.4BSD man page mentions this:

System V has historically implemented character ranges using the syntax
“[c-c]” instead of the “c-c” used by historic BSD implementations and
standardized by POSIX.

--
Christian "naddy" Weisgerber na...@mips.inka.de

Kenny McCormack

unread,
Sep 19, 2016, 12:19:42 PM9/19/16
to
In article <nrosmv$10p$1...@dont-email.me>,
Ed Morton <morto...@gmail.com> wrote:
...
>In what way is it overkill? It's just another UNIX tool you can call to do a
>job, just like you're using tr now, BUT it'll work for all characters and
>doesn't require you to hard-code them.

People often misuse the term "overkill", when what they really mean is
"non-portable". And by "non-portable", I mean "Not necessarily available
on your particular platform". Note that depending on GAWK and, more
importantly, depending on a current version of GAWK with the latest API
stuff in the core and the "ordchr" library properly installed and
available, *is* a reasonable thing to worry about.

Actually, I'm pretty surprised that no one has posted a Perl solution yet.
Given that a standard Debian Linux installation will have Perl installed
but will *NOT* have gawk, it seems reasonable to prefer Perl to gawk here.

P.S. And note that even if you *do* install gawk from the repositories,
you will often get an old cranky version (for a long time, until very
recently, the repos with which I am familiar were dispensing gawk 3.1.8...)

--
People who say they'll vote for someone else because Obama couldn't fix
*all* of Bush's messes are like people complaining that he couldn't cure
cancer, so they'll go and vote for (more) cancer.

Janis Papanagnou

unread,
Sep 19, 2016, 12:50:51 PM9/19/16
to
On 19.09.2016 16:30, Christian Weisgerber wrote:
> On 2016-09-19, Brian Patrie <bpa...@bellsouth.spamisicky.net> wrote:
>
>> Ah, the ever-popular slip of confusing tr(1) syntax with globbing.
>> The [ ] are superfluous (and merely get translated to themselves).
>
> Well, the 4.4BSD man page mentions this:
>
> System V has historically implemented character ranges using the syntax
> “[c-c]” instead of the “c-c” used by historic BSD implementations and
> standardized by POSIX.

A 30+ years old book on my bookshelf describes UNIX "Version 7" commands
(i.e. even older than "System V"); it shows the tr example: tr "a-z" "A-Z"

Janis

Ben Bacarisse

unread,
Sep 19, 2016, 2:54:00 PM9/19/16
to
gaz...@shell.xmission.com (Kenny McCormack) writes:
<snip>
> Actually, I'm pretty surprised that no one has posted a Perl solution
> yet.

Perl has an operator that increments a string: Y -> Z -> AA -> AB so it
may be a natural fit for the OP depending on the actual task at hand:

perl -e '$l="Q";print++$l'

<snip>
--
Ben.

Kaz Kylheku

unread,
Sep 19, 2016, 3:11:24 PM9/19/16
to
I don't use perl, but I "manually fuzzed" the above and found
two language design cluster-fucks in about 10 times that many
seconds:

$ perl -e '$l="Q";print ++$l, "\n"'
R

$ perl -e '$l="Q";print $l+1, "\n"'
1

Inconsistency: the result of ++A is not A + 1.

$ perl -e '$l="Q";print $l+1, " ", ++$l,
"\n"'
1 1

Unsafe behavior: arithmetic operator + has apparently performed a side
effect on $l, changing the outcome of ++$l.

Kenny McCormack

unread,
Sep 19, 2016, 3:24:17 PM9/19/16
to
In article <87k2e7i...@bsb.me.uk>,
I don't do Perl, but I'm pretty sure that it has "ord" and "chr" builtin.

I would consider that a more straightforward approach to this problem, for
the reasons Kaz has outlined.

--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain in
compliance with said RFCs, the actual sig can be found at the following web address:
http://www.xmission.com/~gazelle/Sigs/DanQuayle

James

unread,
Sep 19, 2016, 3:39:04 PM9/19/16
to
On Monday, September 19, 2016 at 12:24:17 PM UTC-7, Kenny McCormack wrote:

> I don't do Perl, but I'm pretty sure that it has "ord" and "chr" builtin.
>
> I would consider that a more straightforward approach to this problem, for
> the reasons Kaz has outlined.
>

$ perl -sle 'print chr(ord($c)+1)' -- -c="C"
D
$ perl -sle 'print chr(ord($c)+1)' -- -c="Z"
[

James

Dan Espen

unread,
Sep 19, 2016, 5:05:01 PM9/19/16
to
Kaz Kylheku <221-50...@kylheku.com> writes:

> On 2016-09-19, Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
>> gaz...@shell.xmission.com (Kenny McCormack) writes:
>><snip>
>>> Actually, I'm pretty surprised that no one has posted a Perl solution
>>> yet.
>>
>> Perl has an operator that increments a string: Y -> Z -> AA -> AB so it
>> may be a natural fit for the OP depending on the actual task at hand:
>>
>> perl -e '$l="Q";print++$l'
>
> I don't use perl, but I "manually fuzzed" the above and found
> two language design cluster-fucks in about 10 times that many
> seconds:
>
> $ perl -e '$l="Q";print ++$l, "\n"'
> R
>
> $ perl -e '$l="Q";print $l+1, "\n"'
> 1

Read the Perlop man page.
No where does it say that "++" is another way of adding.

What it does say is:

The auto-increment operator has a little extra builtin magic to it.
If you increment a variable that is numeric, or that has ever been
used in a numeric context, you get a normal increment. If, however,
the variable has been used in only string contexts since it was set,
and has a value that is not the empty string and matches the pattern
"/^[a-zA-Z]*[0-9]*\z/", the increment is done as a string, preserving
each character within its range, with carry...

and then:

The auto-decrement operator is not magical.

As long as the behavior is documented, I'm fine with it.

> Inconsistency: the result of ++A is not A + 1.
>
> $ perl -e '$l="Q";print $l+1, " ", ++$l,
> "\n"'
> 1 1
>
> Unsafe behavior: arithmetic operator + has apparently performed a side
> effect on $l, changing the outcome of ++$l.

Man page says:

Note that just as in C, Perl doesn't define when the variable is
incremented or decremented. You just know it will be done sometime
before or after the value is returned. This also means that modifying
a variable twice in the same statement will lead to undefined
behavior. Avoid statements like:

$i = $i ++;
print ++ $i + $i ++;

Perl will not guarantee what the result of the above statements is.

As long as the behavior is documented, I'm fine with it.


--
Dan Espen

Thomas 'PointedEars' Lahn

unread,
Sep 19, 2016, 5:29:41 PM9/19/16
to
Alan Mackenzie wrote:

> Ed Morton <morto...@gmail.com> wrote:
>> Why? If you are doing something like this then it's probably in the
>> context of manipulating text and bash is not a tool for manipulating
>> text, it's an environment from which to call tools with a language to
>> sequence those calls.
>
> Having applied a mercurial tag to my repository, I sometimes want to
> apply the "next" tag as well. This involves incrementing a character in
> the tag name.

There is probably a reliable way in Mercurial to get the next tag. It may
involve using the shell to process text output from Mercurial.

--
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.

Thomas 'PointedEars' Lahn

unread,
Sep 20, 2016, 1:34:31 AM9/20/16
to
Very nice solution without arrays, cut(1) or sed(1). However:

1. In this example, the characters in “str” are _not_ in ASCII code point
order. In ASCII, the decimal digits have the *lowest* code points,
followed at some higher code point by the uppercase letters, which are
followed at some higher code point by the lowercase letters.

2. In Bash, (in order to avoid such problems,) it is possible to generate
the string consisting of all ASCII characters, in code point order,
dynamically:

str=$(echo -e "$(printf '\\x%x' $(seq 0 0x7F) )")

[“echo” and “printf” are Bash builtins. Using the "\\u%04x” format and,
if necessary xargs(1), it is even possible to get particular sequences
of Unicode characters or the whole Unicode character set in Bash
4.4.0(1)-rc1. (Which, with PCRE support, would allow to list all
characters in a Unicode character class, without parsing the Unicode
Character Database.)]

seq(1) is not a Bash builtin, but part of, e.g., GNU coreutils. It can be
emulated using a “while” loop if necessary. In this case:

type seq || seq () {
local n=$1
while [ $n -le $2 ]; do printf '%s\n' "$n"; let n++; done
}

Note that for shells that do not support a “local” mechanism but subshells,
variables can be declared and used in a subshell instead. For example:

type seq || seq () {
(
n=$1
while [ $n -le $2 ]; do printf '%s\n' "$n"; let n++; done
)

Rakesh Sharma

unread,
Sep 20, 2016, 2:02:54 AM9/20/16
to
There's nothing unsafe here. This is Perl coercing the variable $l to a numeric due to the "+" operator. The same will be seen in other cases also, e.g., "awk".

Alan Mackenzie

unread,
Sep 20, 2016, 5:24:28 AM9/20/16
to
Hello, Ed.
AWK would be overkill in the same way as using a sledgehammer to crack a
peanut would be. AWK is a beautiful language, very capable, very
powerful, and you're suggesting it's an appropriate tool for nothing more
than "+= 1"? This seems to me to be in bad taste. If I want to get to
the shop on the other side of the street, I don't order a taxi to take me
there. It is my script we're talking about, after all. :-)

>>> .... and you can do this with GNU awk as:

>>> $ awk -l ordchr 'BEGIN{print chr(ord("Q")+1)}'
>>> R

And then, even the core AWK languaage is too awkward, it needing the
loading of a special library.

>>> within the context of whatever other text manipulation you are doing.

>> In the end, I just used

>> echo ch | tr 'ABCDEFGHIJKLMNOPQRSTUVWXY' 'BCDEFGHIJKLMNOPQRSTUVWXYZ'

> You asked for a solution to give you the next ascii character given an
> ascii character, not "the next upper case letter given an upper case
> letter excluding Z".

I was vague and unspecific, saying only what I thought was relevant.

>> , which more than covers the range I'll need. It feels awkward, and
>> there ought to be something better, but it seems there is not.

> The awk solution is better.

The AWK solution is not better in _my_ scripts. :-)

> If you feel it's lengthy and you do want to call it from your shell,
> put it in a shell function:

> $ succ() { awk -v c="$1" -l ordchr 'BEGIN{print chr(ord(c)+1)}'; }
> $ succ C
> D

So, for a "+= 1" operation, I would be calling a function, which would
load an external utility, which would itself have to load a library. All
for "+= 1". I don't like that.

> Regards,

> Ed

Icarus Sparry

unread,
Sep 24, 2016, 2:35:33 PM9/24/16
to
If you are able to restrict yourself to letters (treated in a case
insensitive way) and maybe the numbers then you can do this using just
builtins

succ() {
# Leave off the 0 if you want to have the empty string
# as the successor of Z
local A="123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0"
echo ${A:$((36#$1)):1}
}

Usage would then be

LETTER=$(succ Q)
echo $LETTER

This just uses the "trick" that bash can have constants in bases other
than 10. Here I use 36. Another good base to use would be 62, just make A
be 1-9a-zA-Z. Once we consider the input as a number we just use the
substring operation to pick the nth value from the string.



0 new messages