Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
commands:builtin:let [2012/05/03 16:52]
ormaaj Finally discovered something useful that can be done with let
commands:builtin:let [2015/11/16 04:19] (current)
thebonsai [The let builtin]
Line 1: Line 1:
-====== The let builtin ======+====== The let builtin ​command ​======
  
 ===== Synopsis ===== ===== Synopsis =====
Line 14: Line 14:
  
 ===== Examples ===== ===== Examples =====
-''​let''​ is very similar to [[syntax:​ccmd:​arithmetic_eval | ((]] - the only difference being ''​let''​ is a builtin (simple command), and ''<​nowiki>​((</​nowiki>''​ is a compound command. The arguments to ''​let''​ are therefore subject to all the same expansions and substitutions as any other simple command - requiring proper quoting and escaping - whereas the contents of ''<​nowiki>​((</​nowiki>''​ aren't subject to [[syntax:​expansion:​wordsplit | word-splitting]] or [[syntax:​expansion:​glob | pathname expansion]] (almost never desirable for arithmetic). For this reason, **the [[syntax:​ccmd:​arithmetic_eval | arithmetic compound command]] should generally be preferred over ''​let''​**.+''​let''​ is very similar to [[syntax:​ccmd:​arithmetic_eval | ((]] - the only difference being ''​let''​ is a builtin (simple command), and ''<​nowiki>​((</​nowiki>''​ is a compound command. The arguments to ''​let''​ are therefore subject to all the same expansions and substitutions as any other simple command - requiring proper quoting and escaping - whereas the contents of ''<​nowiki>​((</​nowiki>''​ aren't subject to [[syntax:​expansion:​wordsplit | word-splitting]] or [[syntax:​expansion:​globs | pathname expansion]] (almost never desirable for arithmetic). For this reason, **the [[syntax:​ccmd:​arithmetic_eval | arithmetic compound command]] should generally be preferred over ''​let''​**.
  
 <​code>​ <​code>​
Line 34: Line 34:
 </​WRAP>​ </​WRAP>​
  
-Unlike ''<​nowiki>​((</​nowiki>'',​ being a simple command ''​let''​ has its own environment. In Bash, built-ins that can set variables process any arithmetic under their own environment,​ which enables the effect that the variable effectively ​becomes ​"private" to the arithmetic expression ​unless the variable is also set or modified by the expressionThe value set in the environment ​is a string ​even if the variable ​has previously been given the ''​-i''​ attribute, and even if modified by the expression retains all the same attributes afterwards. These examples demonstrate these, and also that other built-ins do it too, though it would probably be a very unusual corner-case to use this with anything other than ''​let''​.+Unlike ''<​nowiki>​((</​nowiki>'',​ being a simple command ''​let''​ has its own environment. In Bash, built-ins that can set variables process any arithmetic under their own environment,​ which makes the variable effectively "local" to the builtin ​unless the variable is also set or modified by the builtinThis differs ​in other shells, such as ksh93, where environment ​assignments to regular builtins are always local even if the variable ​is modified by the builtin.
  
 <​code>​ <​code>​
Line 44: Line 44:
 declare -- x="​2"​ declare -- x="​2"​
 declare -- y="​3"​ declare -- y="​3"​
 +</​code>​
  
- ~ $ ( declare -i y; y=1+1 z='​z[$(echo $y >&​2)]=0'​ let z,y+=x=y; declare -p x y ) +This can be useful in certain situations where temporary variable is needed.
-1+1 +
-declare -- x="​2"​ +
-declare -i y="​4"​ +
- +
- ~ $ ( y=1+1 declare -'x=( [x=y]=test )'; declare -p x y ) +
-declare -a x='​([0]="​2"​ [2]="​test"​)'​ +
-bash: declare: y: not found +
- +
- ~ $ ( y=1+1 declare -a 'x=( [x=y++]=test )'; declare -p x y ) +
-declare -a x='​([0]="​2"​ [2]="​test"​)'​ +
-declare -- y="​3"​ +
- +
- ~ $ ( y=1+1 printf -v '​x[x=y]'​ %s test; declare -p x y ) +
-declare -a x='​([0]="​2"​ [2]="​test"​)'​ +
-bash: declare: y: not found +
- +
- ~ $ ( y=1+1 printf -v '​x[x=y++]'​ %s test; declare -p x y ) +
-declare -a x='​([0]="​2"​ [2]="​test"​)'​ +
-declare -- y="​3"​ +
-</​code>​+
  
 ===== Portability considerations ===== ===== Portability considerations =====
  
-  * the ''​let''​ command is not specified by POSIX(r). The standard ​alternative is: <​code>​[ "$(( <​EXPRESSION>​ ))" -ne 0 ]</​code>​ +  * the ''​let''​ command is not specified by POSIX(r). The portable ​alternative is: <​code>​[ "$(( <​EXPRESSION>​ ))" -ne 0 ]</code>. To make portable scripts simpler and cleaner, ''​let''​ can be defined as: <code> 
 +# POSIX 
 +let() { 
 +    IFS=, command eval test '​$(($*))'​ -ne 0 
 +
 +</​code>​ Aside from differences in supported arithmetic features, this should be identical to the Bash/Ksh ''​let''​. 
 +  * It seems to be a common misunderstanding that ''​let''​ has some legacy purpose. Both ''​let''​ and [[syntax/​ccmd/​arithmetic_eval | ((...))]] were ksh88 features and almost identical in terms of portability as everything that inherited one also tended to get the other. Don't choose ''​let''​ over ''​((''​ expecting it to work in more places.
   * [[http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​expr.html#​tag_20_42 | expr(1)]] is a command one is likely to come across sooner or later. While it is more "​standard"​ than ''​let'',​ the above should always be preferred. Both [[syntax:​arith_expr | arithmetic expansion]]s and the ''​[''​ test operator are specified by POSIX(r) and satisfy almost all of expr's use-cases. Unlike ''​let'',​ ''​expr''​ cannot assign directly to bash variables but instead returns a result on stdout. ''​expr''​ takes each operator it recognizes as a separate word and then concatenates them into a single expression that's evaluated according to it's own rules (which differ from shell arithmetic). ''​let''​ parses each word it recieves on its own and evaluates it as an expression without generating any output other than a return code.   * [[http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​expr.html#​tag_20_42 | expr(1)]] is a command one is likely to come across sooner or later. While it is more "​standard"​ than ''​let'',​ the above should always be preferred. Both [[syntax:​arith_expr | arithmetic expansion]]s and the ''​[''​ test operator are specified by POSIX(r) and satisfy almost all of expr's use-cases. Unlike ''​let'',​ ''​expr''​ cannot assign directly to bash variables but instead returns a result on stdout. ''​expr''​ takes each operator it recognizes as a separate word and then concatenates them into a single expression that's evaluated according to it's own rules (which differ from shell arithmetic). ''​let''​ parses each word it recieves on its own and evaluates it as an expression without generating any output other than a return code.
 +  * For unknown reasons, ''​let''​ is one of the Bash commands with special parsing for arguments formatted like compound array assignments. See: [[commands/​builtin/​eval#​portability_considerations | eval]] for details. There are no known practical uses for this. Parentheses are treated as grouping operators and compound assignment is not possible by arithmetic expressions.
  
 ===== See also ===== ===== See also =====