Looking for an easy way to make a random number, i came across a web page that used the follow snip of code
echo $[ ( $RANDOM % $DIE_SIDES ) + 1 ]
What is the purpose of the $[. Googling did not reveal the answer I seek. Thanks
The $[expression] construct is used for arithmetic; $[1+1], for example, returns 2. You can also say $((expression)) or expr 1 + 1. The expr command version is old-school and should work in any shell, the $[expression] and $((expression)) versions work in bash but I'm not sure if they're covered by POSIX.
Update: The $[expression] form is a bash extension, the $((expression)) form is specified for the POSIX shell.
Related
For reference, I'm using this version of the shell.
I'm looking to evaluate a math expression containing exponents. How can I do so? expr isn't available in es-shell, and neither do the double parends work (as they do in other shells).
The expression I want to evaluate is 2^69 (2 to the 69th power). I've tried with both ** and ^ for exponentiation.
I'm looking for a solution that doesn't use an external calculator, hopefully pure es-shell code.
Most Unix shells delegate math to some other command. bc is probably available on your machine, since it's a POSIX utility. Invoke it from es like this:
; echo `{echo '2 ^ 69' | bc}
590295810358705651712
I am working on a very simple bash script and I'm having a problem with understating why deprecated $[] is working flawlessly, while $(()) seems to break the whole thing.
The code I'm referring to is:
for i in {1..10};
do
printf %4d $[{1..10}*i]
echo
done
In this version I am having no issues, yet I wouldn't like to use deprecated bash elements, that's why I wanted to switch to $(()).
Unfortunately, as soon as I change my code to:
printf %4d $(({1..10}*i))
I receive an error:
./script_bash.sh: line 8: {1..10}*i: syntax error: argument expected (error token is "{1..10}*i")
I'd be thankful for some help with this one...
Setting the way back machine for 1990.
Bash implemented the $[] syntax per POSIX P1003.2d9 (circa 1990), which was a draft of the released P1003.2-1992. In the two years between draft and standard, POSIX had instead settled on the ksh88 $(()) syntax and behaviors. Chet Ramey (bash maintainer) had this to say, back in 2012:
Bash... implemented $[...] because there was no other
syntax at the time, and to gain some operational experience with
arithmetic expansion in the shell. Bash-1.14... lists both forms of arithmetic expansion, but by
the time bash-2.0 was released in 1995, the manual referred only to
the $((...)) form.
This suggests to me that the $[] form was experimental, and it had certain behaviors (like brace expansion) that were specified into oblivion when POSIX adopted the $(()) syntax. Those experimental behaviors were left in, since there were already scripts in the wild relying on them (remember more than 2 years had elapsed).
Chet makes clear in that same thread that the $[] form is obsolete, but not deprecated:
Now, it's hardly any problem to keep dragging the $[...] syntax along.
It takes only a few dozen bytes of code. I have no plans to remove it.
The current POSIX standard, C.2.6 Word Expansions > Arithmetic Expansion mentions the syntax (emphasis mine):
In early proposals, a form $[expression] was used. It was functionally equivalent to the "$(())" of the current text, but objections were lodged that the 1988 KornShell had already implemented "$(())" and there was no compelling reason to invent yet another syntax. Furthermore, the "$[]" syntax had a minor incompatibility involving the patterns in case statements.
So the as-implemented behavior in bash isn't quite to specification, but since there are no plans to remove it, I see no reason to forgo its benefits if it neatly solves your problem. However, as pointed out by #Barmar's comment, it'd be A Good Idea to comment the code and link it here so future developers know what the heck you mean!
$(()) is for arithmetic expressions, and brace expansion isn't done in arithmetic.
Make an array with a loop:
for i in {1..10}
do
vals=()
for j in {1..10}
do
vals+=($((i*j)))
done
printf "%4d" ${vals[#]}
done
printf %4d $(({1..10}*i))
does not work because of the order in which parameters are expanded in bash. The brace expansion ({}) is done earlier than arithmetic expansion ($(())) by bash. Your code would definitely work if it were other way around.
From man bash:
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and pathname expansion.
Ran across some bash like this. This question asks for explanation, rather than solution, but here would be a $(())-way of expressing this.
for i in {1..10}; do
printf %4d $(eval echo '$(('{1..10}'*i))')
echo
done
Brace expansion is inhibited inside an arithmetic expansion like it is for parameter expansion.
(bash manual)
To avoid conflicts with parameter expansion, the string ‘${’ is not
considered eligible for brace expansion, and inhibits brace expansion
until the closing ‘}’.
I have a check that checks how many files are missing in the database. Everything works but when my code runs and outputs the results, there are 3 files missing but it is displayed like "+1+1+1".
The code I am using is errcount=$errcount+1
Why does the code not accumulate the results?
Here is one way:
errcount=$(expr $errcount + 1)
(Note the spaces)
This is a string operation:
errcount=$errcount+1
It does not do math.
POSIX shells
If you want the shell to do arithmetic, you can use the $((...)) construct:
errcount=$((errcount+1))
Bash
Bash has additional non-POSIX extensions for incrementing a variable:
((errcount=errcount+1))
Or:
((errcount++))
Is there a way to implement the following using 'for' in KornShell (ksh)?
Here is the C equivalent:
for(i=1;i<20;i++)
{
printf("%d",i);
}
I was wondering if this can be implemented using just 'for' and not 'while'
I tried the following, it does not seem to work.
for i in [1-20]
do
print $i
done
Please let me know your ideas and solutions.
Not really an answer, but an FYI to casual ksh users.
Edit 2019-05-12 (Minor edits below in bold, other info is now stricken).
To clarify on several comments here, there are 2 ksh's available in typical vendor installations (non-Linux (maybe them too?)).
Solaris and AIX have a ksh and ksh93 (probably true for other vendors too). The base ksh is also known as ksh88. Ksh93 is described in The New Kornshell Command and Programming Language, 1995
Linux systems that have a true ksh (not pdksh), mostly use ksh93 named as ksh.
Finally, to further confuse things, don't let the 1995 pub date trick you, ksh continues under was under active development by David Korn and Glen Fowler at AT&T until 2012?. Versions were released 2-3X per year. Some Linux versions pick up the newer versions.
These newer versions have very advanced features
(most of this taken from AT&T research UWIN page. search for the link 'notes and changes' (dead link) )
compound variables composed like c structs (no c datatypes, just typeset decls) (one user claims a 500 Meg in-memory struct)
Double precision floating point arithmetic with full C99 arithmetic ..The numbers Inf and NaN can be used in arithmetic expressions.
TAB-TAB completion generates a numbered list of completions ...
Support for processing/handling multibyte locales (e.g., en_US.UTF-8, hi_IN.UTF-8, ja_JP.eucJP, zh_CN.GB18030, zh_TW.BIG5 etc.) ...
/dev/(tcp|udp|sctp)/host/sevrice now handles IPv6 addresses ...
... seek on a file by offset or content with new redirection operators.
A new --showme option which allows portions of a script to behave as if -x were specified while other parts execute as usual. ...
The [[...]] operator =~ has been added which compares the string to an extended regular expression ....
The printf(1) builtin has been extended to support the = flag for centering a field ... (and others) ...
view-pathing
"Most of the utilities were developed by AT&T and conform to POSIX.2 and X/Open."
(note that ...s in above, usually indicate some qualifying information removed)
Korn and Fowler had also produced an advanced environment, UWIN (Unix for Windows) for people that use systems like Mingw or Cygwin, that would be worthy of a separate post. The downside for UWIN is,
not same set of utilities as you find in your favorite Linux.
Another file compilation environment that pretty much has to use MS Visual C (gcc support via Mingw is said to be on-the-way),
a very small support community,
the AT&T Common Public License V 1.0 Eclipse Public License* is not GNU.
See UWin main page (dead link) : unfortunately out of date, better to nose around in the dnld link above. Hmm, this is much better Glenn Fowler's FAQ for UWin (also dead, Time Machine anyone?).
I hope this helps!
Edit 2019-05-12 . The reason for the dead links?
David Korn and Glen Fowler Laid Off (at AT&T, 2012?
Information later surfaced that they are working at Google. I can't confirm this, so consider it as an old rumor.
AND see Is Ksh93 dead?
There still seems to be some activity at the ast git-hub site . ast is the over-arching package that includes ksh93. You can get the fresh source code there and compile it.
Here is the text of the project description. (There is considerably more information in the README.md).
KSH93
This repository contains the AT&T Software Technology (AST) toolkit
from AT&T Research. As of November 2017 the development focus has been
shifted to the ksh (or ksh93) command and supporting code required to
build it.
The non-ksh code of the AST project is no longer being actively
maintained. If you are interested in the non-ksh code see below for
details on which branches contain the full AST code base.
The project only supports systems where the compiler and underlying
hardware is ASCII compatible. This includes Linux on IBM zSeries but
not z/OS. The nascent, incomplete, support for EBCDIC has been
removed. See issue #742.
*
The EPL replaced AT&T's original CPL.
Unfortunately, it looks as if ksh does not have support for range-based brace expansion or support the (( )) construct so to do this compactly, you'll need to call the external binary seq like so:
for i in $(seq 1 20); do
echo $i
done
ksh93 supports the C-like (( ...;...; ...)):
for ((i=1;i<20;i+=1)); do
printf "%d " $i
done && print
This will produce:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Heck, even the old syntax (using '{' ... '}' instead of 'do ... done' will work):
for((i=1;i<20;i+=1))
{
printf "%d " $i
} && print
In older shells, you can still get the same effect with
i=1 && while ((i<20)); do
printf "%d " $i
((i+=1))
done && print
ksh93 offers braceexpansion also if "braceexpand" is "on". Check with "set -o" and then use curly braces {}
for i in {1..20}
do
print $i
done
I have just stumbled upon the bash syntax:
foo=42
bar=$[foo+1] # evaluates an arithmetic expression
When I Googled for this, I found http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html#sect_03_04_05:
3.4.6. Arithmetic expansion
Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is:
$(( EXPRESSION ))
...
Wherever possible, Bash users should try to use the syntax with square brackets:
$[ EXPRESSION ]
However, this will only calculate the result of EXPRESSION, and do no tests...
In my bash man page I can only find the $(( EXPRESSION )) form such as:
foo=42
bar=$((foo+1)) # evaluates an arithmetic expression
So what tests are not performed with $[...] that do with $((...)), or is the $[...] just a legacy version of $((...))?
The manpage for bash v3.2.48 says:
[...] The format for arithmetic expansion is:
$((expression))
The old format $[expression] is deprecated and will be removed in upcoming versions
of bash.
So $[...] is old syntax that should not be used anymore.
#sth is entirely correct. And in case you are curious about why a more verbose syntax is now in favor, check out this old email from the mailing list.
http://lists.gnu.org/archive/html/bug-bash/2012-04/msg00033.html
“In early proposals, a form $[expression] was used. It was functionally
equivalent to the "$(())" of the current text, but objections were
lodged that the 1988 KornShell had already implemented "$(())" and
there was no compelling reason to invent yet another syntax.
Furthermore, the "$[]" syntax had a minor incompatibility involving
the patterns in case statements.”
I am not sure that I like the rationale “but someone has already done this more verbosely,” but there you have it—maybe the case-statement problem was more compelling than I am imagining from this obscure mention?