[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is bash dying or dead (was Re: 4.1 is "$((( ))) an 'official operato

From: Eric Blake
Subject: Re: Is bash dying or dead (was Re: 4.1 is "$((( ))) an 'official operator, if $(( )) isn't?
Date: Wed, 10 Aug 2011 16:40:27 -0600
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv: Gecko/20110621 Fedora/3.1.11-1.fc14 Lightning/1.0b3pre Mnenhy/0.8.3 Thunderbird/3.1.11

On 08/10/2011 03:59 PM, Linda Walsh wrote:

Is this a fluke, due to the above changes NOT being 4.1? Or is this
construction going to break in 4.2:

'$((( )))'

According to POSIX, this construction should be parsed as an arithmetic substitution $(()) where the expression is (expr), if at all possible; but if not possible, then it may also be parsed as a command substitution $() around either a double-subshell (()) or a shell extension of an arithmetic evaluation.

And since POSIX correctly states that this is implementation-specific, and involves shell heuristics, you are best off adding spaces to make it explicit which form you intended.

I wanted to evaluate something and assign result to a var.

gives me 'a=0', but

Not portable - lack of spacing means you fall foul of the ambiguity traps.

a=$( ((-48-16+2**6)) )
will give 'a=<nothing>' -- understandable since the arith expression
merely sets status, it doesn't yield up it's value.

Not portable. While bash happened to use (( as an arith expression, other shells may treat it as a double-subshell, and try to execute the command that results from expanding the glob -48-16+2**6 as a file name.

How do I assign something to a?


a=$(( (-48-16+2**6)))

if you intended to assign a to the arithmetic expansion of the expression (-48-16+2**6); however, you are _still_ falling foul of using a bash extension (not all shells understand ** in arithmetic expansions), so you may still end up executing a command substitution over a double-subshell unless you rewrite your arithmetic expression to comply with POSIX (but POSIX doesn't have any way to do exponentiation).

If I use:
((a=-48-16+2**6)) ; throws an error. if -e is on, script exits

Bash extension. But the exit status of (()) makes sense as being non-zero for a result of 0, since the intended use of (()) is in control loops where the loop counter reaching 0 should abort the loop. And once the exit status makes sense, then the interaction with 'set -e' makes sense. Rather, you should realize that 'set -e', when rigidly defined, causes what seem to be very unintuitive results, and that NO AMOUNT OF COMPLAINING will ever make it more intuitive, so you are better off learning how to properly script without using 'set -e' as a crutch.

Since 'let' functions the same as the above, then

'let' is a bash extension, not portable to POSIX.

Seems like POSIX has made bash as useful (or less so in some ways) as
borne shell.

Not true. POSIX has made bash more useful by making the portable constructs well-defined whether you are running on bash or any other portable shell, while still leaving bash room to provide extensions like (()) and let.

It seems like POSIX is trying to kill off the usefulness of Bash -- and
that Bash is becoming 'sh+', rather than 'Bash'.

Not true. Join the Austin Group, and you will see that the goal of POSIX is to standardize existing practice into something that can be commonly implemented by multiple people and safely relied on by multiple existing scripts, rather than worrying about implementation-specific extensions all over the place. If you can code to a common subset, your program becomes much more useful in practice.

POSIX is braindead.

I'm sorry you think so, but ranting on this list won't change POSIX. If you don't like what POSIX is doing, then join the Austin Group (membership is free of charge) and submit your suggestions for improvements.

Bash shouldn't follow posix unless in --posix mode, as posix mode is
worthless to program in -- as evidenced by the fact that you can no
longer do any calculation safely with let or (()),

'let' and (()) are not specified by POSIX, so you can't portably use them in --posix mode in the first place. --posix is VERY useful; it is what allows you to write scripts that work in bash, dash, ksh, zsh, and several other shells, without having to rewrite them every time you copy the script to a new machine.

> without fear that
your script will randomly die (oh just don't use command-exit-error
checking...) and you can no longer call functions safely.

'set -e' and function calls are one of the _fundamental_ non-intuitive designs of the historical shell. They were designed independently, and do not interact well. But given the latest POSIX wording, you can at least apply consistent rules and rationally explain each behavior that you are seeing, and why what appears unintuitive actually complied with the standard; and you _can't_ change that non-intuitiveness without breaking existing scripts that have come to rely on the quirks as currently codified by POSIX.. The problem was that even in POSIX 2008, the POSIX wording had holes, it is not until the TC1 wording that the wording was tightened enough to actually be implementable by bash in a manner that matched ksh.

Bash is becoming very unstable -- programs that work in 3.1 won't
necessarily work in 3.2, those in 3.2 aren't compat with 4.0, 4.0 is
different than 4.1, and now 4.2 is different than 4.1.

That's because older bash has had bugs where it doesn't comply with POSIX, and those bugs have been fixed, but sometimes the fixes have consequences on the bash extensions. But if you use the POSIX subset, rather than the bash extensions, you should notice that newer bash is better, not worse, than older bash when it comes to running portable scripts.

How can people write stable scripts in an enironment of constant change?

By sticking to the common denominator that is known to work.

Please people, am I being 'over-reactive'? Or are these valid

At least in my view, you are coming across as over-reactive and ranting, even if that was not your intent.

Eric Blake   address@hidden    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

reply via email to

[Prev in Thread] Current Thread [Next in Thread]