Re: local -r issue in conjunction with trap
Date:Fri, 15 Jul 2022 16:13:40 + (UTC) From:Robert Stoll Message-ID: <1549965963.26496.1657901620717.javamail.zim...@tegonal.com> | Unfortunately I have never built bash on my own and it would probably | take me too much time to do it. It probably wouldn't, fetch the tarball, unpack it, ./configure && make and you're done (after a short wait). But that's only useful if a newer version fixes some problem, or if you want to make changes of your own - the latter can certainly take time. | Thus, I am writing to this e-mail in the hope that someone more | experienced can try to reproduce it with the latest version. There is no need, what you're seeing isn't a bug. readonly variables cannot be made local, the bash man page even says so ... The return status is 0 unless local is used outside a function, an invalid name is supplied, or name is a readonly variable. The "readonly in a function can be made local in another function" thing most likely is a bug - but (as I have said before, and will keep on saying) bash's view of what a local variable should be is simply weird. It isn't true lexical scoping, like Korn was (IMO, inadvisedly) trying to achieve in ksh, and it isn't simple and sane like other shells, just a mess. One last comment - you probably shouldn't be using read only variables at all, they're a rather special use case, and attempting to make a local read only variable is weird in itself, but with the same name as some other read only variable, is simply perverse. Read only vars are best left for applications which need something they can depend on not being able to be changed (by anything - which is why making one local is not supposed to work) in which case they tend to have names you're not likely to trip over by accident when making a local var in a function. kre
Gettings LINES and COLUMNS from stderr instead of /dev/tty
Hello, I'm just wondering that bash (reproduced with 5.2-rc1 under Debian 11) seems to determine LINES and COLUMNS from stderr. For example, this will lead to strange results when starting the script #!/bin/bash shopt -s checkwinsize trap 'echo $LINES $COLUMNS' SIGWINCH while true; do sleep 0.1; done with standard error redirected to a file (or - even more strange ;-) - another terminal). A quick POC shows that replacing tty = input_tty (); with tty = open( "/dev/tty", O_RDONLY ); in get_new_windows_size in lib/sh/winsize.c gives the "expected" result. In case there is some reason not to use /dev/tty, wouldn't it then be better to ask stdin instead of stderr? The script will most probably be interested in the size of device it is writing to, not the one it is logging to. Best regards Martin
Arithmetic expression: interest in unsigned right shift?
Hello. I realized there is no unsigned right shift in bash arithmetic expression, and thought maybe there is interest. This is a not even compile-tested diff against 5.1.16. (Using same tab/space as in surroundings.) A nice Sunday i wish everyone. diff -Napru bash-5.1.orig/expr.c bash-5.1/expr.c --- bash-5.1.orig/expr.c2022-07-16 19:35:21.900221532 +0200 +++ bash-5.1/expr.c 2022-07-16 19:37:23.243552559 +0200 @@ -32,7 +32,7 @@ "**"[(exponentiation)] "*", "/", "%" "+", "-" - "<<", ">>" + "<<", ">>", ">>>" "<=", ">=", "<", ">" "==", "!=" "&" @@ -41,7 +41,7 @@ "&&" "||" "expr ? expr : expr" - "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=","^=","|=" , [comma] (Note that most of these operators have special meaning to bash, and an @@ -112,13 +112,14 @@ #define LOR8 /* "||" Logical OR */ #define LSH9 /* "<<" Left SHift */ #define RSH10 /* ">>" Right SHift */ -#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ -#define COND 12 /* exp1 ? exp2 : exp3 */ -#define POWER 13 /* exp1**exp2 */ -#define PREINC 14 /* ++var */ -#define PREDEC 15 /* --var */ -#define POSTINC16 /* var++ */ -#define POSTDEC17 /* var-- */ +#define URSH 11 /* ">>>" Unsigned right SHift */ +#define OP_ASSIGN 12 /* op= expassign as in Posix.2 */ +#define COND 13 /* exp1 ? exp2 : exp3 */ +#define POWER 14 /* exp1**exp2 */ +#define PREINC 15 /* ++var */ +#define PREDEC 16 /* --var */ +#define POSTINC17 /* var++ */ +#define POSTDEC18 /* var-- */ #define EQ '=' #define GT '>' #define LT '<' @@ -578,6 +579,9 @@ expassign () case RSH: lvalue >>= value; break; + case URSH: + lvalue = (uintmax_t)lvalue >> value; + break; case BAND: lvalue &= value; break; @@ -837,7 +841,7 @@ expshift () val1 = exp3 (); - while ((curtok == LSH) || (curtok == RSH)) + while ((curtok == LSH) || (curtok == RSH) || (curtok == URSH)) { int op = curtok; @@ -846,8 +850,10 @@ expshift () if (op == LSH) val1 = val1 << val2; - else + else if (op == RSH) val1 = val1 >> val2; + else + val1 = (uintmax_t)val1 >> val2; lasttok = NUM; } @@ -1251,6 +1257,7 @@ _is_multiop (c) case LOR: case LSH: case RSH: +case URSH: case OP_ASSIGN: case COND: case POWER: @@ -1424,7 +1431,19 @@ readtok () } else if ((c == GT) && (c1 == GT)) { - if (*cp == '=') + if (*cp == GT) + { + cp++; + if (*cp == '=') + { + assigntok = URSH; /* a >>>= b */ + c = OP_ASSIGN; + cp++; + } + else + c = URSH; + } + else if (*cp == '=') { assigntok = RSH; /* a >>= b */ c = OP_ASSIGN; --steffen | |Der Kragenbaer,The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)
Re: Arithmetic expression: interest in unsigned right shift?
Steffen Nurpmeso writes: > I realized there is no unsigned right shift in bash arithmetic > expression, and thought maybe there is interest. This would be difficult to define cleanly. Currently, arithmetic values are considered to be signed, and >> operates on them as such. So $ echo $(( 1 >> 1 )) 0 $ echo $(( 2 >> 1 )) 1 $ echo $(( 3 >> 1 )) 1 $ echo $(( (-1) >> 1 )) -1 $ echo $(( (-2) >> 1 )) -1 $ echo $(( (-3) >> 1 )) -2 $ echo $(( (-4) >> 1 )) -2 $ For positive values, unsigned right shift would be the same as >>. But for negative numbers, the value has to be cast into an unsigned value, which is then right-shifted (equivalently, divided by a power of 2), and the resulting value then has to be cast back into a signed value. But that will depend on (reveal) the word length of Bash arithmetic computation: (-1) >>> 1 will be equal to 2#0..., which prints as a positive number. In contrast the current Bash arithmetic model is "word-length agnostic as long as you don't overflow", it acts as if the values are mathematical integers. Dale
Re: Gettings LINES and COLUMNS from stderr instead of /dev/tty
Martin Schulte writes: > I'm just wondering that bash (reproduced with 5.2-rc1 under Debian 11) > seems to determine LINES and COLUMNS from stderr. It's not clear to me that the manual page says where the LINES and COLUMNS values are obtained from. Dale
Re: local -r issue in conjunction with trap
Robert Stoll writes: > test1 # works as exit happens outside of test1 > test2 # fails with ./src/test.sh: line 6: local: readonlyVar: readonly > variable Beware that you haven't specified what you mean by "works" and "fails". I assume from the context that "fails" means "produces an error message", but it's much hard to guess what "works" means. In general, when reporting a problem, always explicitly answer "What do I expect to happen?" and "What happens?". Dale
Re: Arithmetic expression: interest in unsigned right shift?
Hi Steffen, thanks for that. It will be especially useful for defining (( MAXINT = ~0 >>> 1 )). This reminds me of some other operations I've been meaning to implement, including true modulus +% (where the sign of the result always matches the divisor) with the corresponding flooring division +/, binary ?: (rather than ternary), non-modulus shifts (so that 1>>32 is 0 on both 32- and 64-bit platforms). It should be noted that non-parameterized functions already exist, though they're awkward to use: f='x*x+y*y' # reusable function $(( x=4, y=3, f )) # 25 $(( x=10, y=2, f )) # 104 The key to parameterized functions is some form of expression-local variables to hold the arguments and other intermediate calculations, and a sane syntax for defining them. More ambitiously, I'd like parameterized numeric functions, bigints, floating point, and overflow trapping. I'm wondering how best to introduce floating point. It seems like there are three feasible approaches: (1) use the existing syntax and operators with automatic detection based on whether the arguments are non-integers. (Although this is what C does, I wouldn't recommend it, because it can result in surprises like 1.5+3/2 → 2.5 where 3/2 is evaluated to 1 before 1+1.5 gets handled as FP. It also means guesswork to pick the appropriate precision for division.) (2) Some sort of marker for the entire expression; for $((…)) it could be useful to allow the expression to be prefaced by a printf format specifier, from which the type of operation can be inferred (including as signed/unsigned, fixing the unsigned right shift btw). Then you get to write $(( %#x 27 )) # 0x1b $(( %.4f 20/3 )) # 6.6667 For the statement form it's still necessary to specify how assignment to a string variable should work, so I would use the same there for consistency. (( %u maxint=~0>>1 )) # correct unsigned operation (3) Extend the existing operators where floating point gives the correct integer result with integer arguments, but define new ones where they differ, especially division // (which is why I wouldn't use // for flooring division). This just leaves open the question of how integer overflow should be handled. Complex numbers and Unicode variable names would be nice too, so that I could write (( y = R*sin(θ) )) or even (( c = ε ** ( a * √-1 * π ) )), but that's much further away. On Sun, 17 Jul 2022, 03:44 Steffen Nurpmeso, wrote: > Hello. > > I realized there is no unsigned right shift in bash arithmetic > expression, and thought maybe there is interest. > This is a not even compile-tested diff against 5.1.16. > (Using same tab/space as in surroundings.) > > A nice Sunday i wish everyone. > > diff -Napru bash-5.1.orig/expr.c bash-5.1/expr.c > --- bash-5.1.orig/expr.c2022-07-16 19:35:21.900221532 +0200 > +++ bash-5.1/expr.c 2022-07-16 19:37:23.243552559 +0200 > @@ -32,7 +32,7 @@ > "**"[(exponentiation)] > "*", "/", "%" > "+", "-" > - "<<", ">>" > + "<<", ">>", ">>>" > "<=", ">=", "<", ">" > "==", "!=" > "&" > @@ -41,7 +41,7 @@ > "&&" > "||" > "expr ? expr : expr" > - "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" > + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", > "&=","^=","|=" > , [comma] > > (Note that most of these operators have special meaning to bash, and an > @@ -112,13 +112,14 @@ > #define LOR8 /* "||" Logical OR */ > #define LSH9 /* "<<" Left SHift */ > #define RSH10 /* ">>" Right SHift */ > -#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ > -#define COND 12 /* exp1 ? exp2 : exp3 */ > -#define POWER 13 /* exp1**exp2 */ > -#define PREINC 14 /* ++var */ > -#define PREDEC 15 /* --var */ > -#define POSTINC16 /* var++ */ > -#define POSTDEC17 /* var-- */ > +#define URSH 11 /* ">>>" Unsigned right SHift */ > +#define OP_ASSIGN 12 /* op= expassign as in Posix.2 */ > +#define COND 13 /* exp1 ? exp2 : exp3 */ > +#define POWER 14 /* exp1**exp2 */ > +#define PREINC 15 /* ++var */ > +#define PREDEC 16 /* --var */ > +#define POSTINC17 /* var++ */ > +#define POSTDEC18 /* var-- */ > #define EQ '=' > #define GT '>' > #define LT '<' > @@ -578,6 +579,9 @@ expassign () > case RSH: > lvalue >>= value; > break; > + case URSH: > + lvalue = (uintmax_t)lvalue >> value; > + break; > case BAND: > lvalue &= value; > break; > @@ -837,7 +841,7 @@ expshift () > >val1 = exp3 (); > > - while ((curtok == LSH) || (curtok == RSH)) > + while ((curtok == LSH) || (curtok == RSH) || (curtok == URSH)) > { >int op = curtok; > > @@ -846,8 +850,10 @@ expshift () > >if (op == LSH) > val1 = va
Re: Arithmetic expression: interest in unsigned right shift?
Printf %u already reveals the word size, as do most kinds of overflow - albeit messily, like $((3**40)) At least by explicitly exposing the word size in a controlled manner, we can write code that avoids unintended overflow. -Martin On Sun, 17 Jul 2022, 11:54 Dale R. Worley, wrote: > Steffen Nurpmeso writes: > > I realized there is no unsigned right shift in bash arithmetic > > expression, and thought maybe there is interest. > > This would be difficult to define cleanly. > > Currently, arithmetic values are considered to be signed, and >> > operates on them as such. So > > $ echo $(( 1 >> 1 )) > 0 > $ echo $(( 2 >> 1 )) > 1 > $ echo $(( 3 >> 1 )) > 1 > $ echo $(( (-1) >> 1 )) > -1 > $ echo $(( (-2) >> 1 )) > -1 > $ echo $(( (-3) >> 1 )) > -2 > $ echo $(( (-4) >> 1 )) > -2 > $ > > For positive values, unsigned right shift would be the same as >>. But > for negative numbers, the value has to be cast into an unsigned value, > which is then right-shifted (equivalently, divided by a power of 2), and > the resulting value then has to be cast back into a signed value. > > But that will depend on (reveal) the word length of Bash arithmetic > computation: (-1) >>> 1 will be equal to 2#0..., which prints > as a positive number. In contrast the current Bash arithmetic model is > "word-length agnostic as long as you don't overflow", it acts as if the > values are mathematical integers. > > Dale > >