github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/docs/commands/for.md (about) 1 # `for` 2 3 > A more familiar iteration loop to existing developers 4 5 ## Description 6 7 This `for` loop is fills a small niche where `foreach` or `formap` are 8 inappropiate in your script. It's generally not recommended to use `for` 9 because it performs slower and doesn't adhere to Murex's design 10 philosophy. However it does offer additional flexibility around recursion. 11 12 ## Usage 13 14 ``` 15 for ( variable; conditional; incrementation ) { code-block } -> <stdout> 16 ``` 17 18 ## Examples 19 20 ``` 21 » for ( i=1; i<6; i++ ) { echo $i } 22 1 23 2 24 3 25 4 26 5 27 ``` 28 29 ## Detail 30 31 ### Syntax 32 33 `for` is a little naughty in terms of breaking Murex's style guidelines due 34 to the first parameter being entered as one string treated as 3 separate code 35 blocks. The syntax is like this for two reasons: 36 37 1. readability (having multiple `{ blocks }` would make scripts unsightly 38 2. familiarity (for those using to `for` loops in other languages 39 40 The first parameter is: `( i=1; i<6; i++ )`, but it is then converted into the 41 following code: 42 43 1. `let i=0` - declare the loop iteration variable 44 2. `= i<0` - if the condition is true then proceed to run the code in 45 the second parameter - `{ echo $i }` 46 3. `let i++` - increment the loop iteration variable 47 48 The second parameter is the code to execute upon each iteration 49 50 ### Better `for` loops 51 52 Because each iteration of a `for` loop reruns the 2nd 2 parts in the first 53 parameter (the conditional and incrementation), `for` is very slow. Plus the 54 weird, non-idiomatic, way of writing the 3 parts, it's fair to say `for` is 55 not the recommended method of iteration and in fact there are better functions 56 to achieve the same thing...most of the time at least. 57 58 For example: 59 60 ``` 61 a [1..5] -> foreach i { echo $i } 62 1 63 2 64 3 65 4 66 5 67 ``` 68 69 The different in performance can be measured. eg: 70 71 ``` 72 » time { a [1..9999] -> foreach i { out <null> $i } } 73 0.097643108 74 75 » time { for ( i=1; i<10000; i=i+1 ) { out <null> $i } } 76 0.663812496 77 ``` 78 79 You can also do step ranges with `foreach`: 80 81 ``` 82 » time { for ( i=10; i<10001; i=i+2 ) { out <null> $i } } 83 0.346254973 84 85 » time { a [1..999][0,2,4,6,8],10000 -> foreach i { out <null> $i } } 86 0.053924326 87 ``` 88 89 ...though granted the latter is a little less readable. 90 91 The big catch with using `a` piped into `foreach` is that values are passed 92 as strings rather than numbers. 93 94 ### Tips when writing JSON inside for loops 95 96 One of the drawbacks (or maybe advantages, depending on your perspective) of 97 JSON is that parsers generally expect a complete file for processing in that 98 the JSON specification requires closing tags for every opening tag. This means 99 it's not always suitable for streaming. For example 100 101 ``` 102 » ja [1..3] -> foreach i { out ({ "$i": $i }) } 103 { "1": 1 } 104 { "2": 2 } 105 { "3": 3 } 106 ``` 107 108 **What does this even mean and how can you build a JSON file up sequentially?** 109 110 One answer if to write the output in a streaming file format and convert back 111 to JSON 112 113 ``` 114 » ja [1..3] -> foreach i { out (- "$i": $i) } 115 - "1": 1 116 - "2": 2 117 - "3": 3 118 119 » ja [1..3] -> foreach i { out (- "$i": $i) } -> cast yaml -> format json 120 [ 121 { 122 "1": 1 123 }, 124 { 125 "2": 2 126 }, 127 { 128 "3": 3 129 } 130 ] 131 ``` 132 133 **What if I'm returning an object rather than writing one?** 134 135 The problem with building JSON structures from existing structures is that you 136 can quickly end up with invalid JSON due to the specifications strict use of 137 commas. 138 139 For example in the code below, each item block is it's own object and there are 140 no `[ ... ]` encapsulating them to denote it is an array of objects, nor are 141 the objects terminated by a comma. 142 143 ``` 144 » config -> [ shell ] -> formap k v { $v -> alter /Foo Bar } 145 { 146 "Data-Type": "bool", 147 "Default": true, 148 "Description": "Display the interactive shell's hint text helper. Please note, even when this is disabled, it will still appear when used for regexp searches and other readline-specific functions", 149 "Dynamic": false, 150 "Foo": "Bar", 151 "Global": true, 152 "Value": true 153 } 154 { 155 "Data-Type": "block", 156 "Default": "{ progress $PID }", 157 "Description": "Murex function to execute when an `exec` process is stopped", 158 "Dynamic": false, 159 "Foo": "Bar", 160 "Global": true, 161 "Value": "{ progress $PID }" 162 } 163 { 164 "Data-Type": "bool", 165 "Default": true, 166 "Description": "ANSI escape sequences in Murex builtins to highlight syntax errors, history completions, {SGR} variables, etc", 167 "Dynamic": false, 168 "Foo": "Bar", 169 "Global": true, 170 "Value": true 171 } 172 ... 173 ``` 174 175 Luckily JSON also has it's own streaming format: JSON lines (`jsonl`). We can 176 `cast` this output as `jsonl` then `format` it back into valid JSON: 177 178 ``` 179 » config -> [ shell ] -> formap k v { $v -> alter /Foo Bar } -> cast jsonl -> format json 180 [ 181 { 182 "Data-Type": "bool", 183 "Default": true, 184 "Description": "Write shell history (interactive shell) to disk", 185 "Dynamic": false, 186 "Foo": "Bar", 187 "Global": true, 188 "Value": true 189 }, 190 { 191 "Data-Type": "int", 192 "Default": 4, 193 "Description": "Maximum number of lines with auto-completion suggestions to display", 194 "Dynamic": false, 195 "Foo": "Bar", 196 "Global": true, 197 "Value": "6" 198 }, 199 { 200 "Data-Type": "bool", 201 "Default": true, 202 "Description": "Display some status information about the stop process when ctrl+z is pressed (conceptually similar to ctrl+t / SIGINFO on some BSDs)", 203 "Dynamic": false, 204 "Foo": "Bar", 205 "Global": true, 206 "Value": true 207 }, 208 ... 209 ``` 210 211 #### `foreach` will automatically cast it's output as `jsonl` _if_ it's STDIN type is `json` 212 213 ``` 214 » ja [Tom,Dick,Sally] -> foreach name { out Hello $name } 215 Hello Tom 216 Hello Dick 217 Hello Sally 218 219 » ja [Tom,Dick,Sally] -> foreach name { out Hello $name } -> debug -> [[ /Data-Type/Murex ]] 220 jsonl 221 222 » ja [Tom,Dick,Sally] -> foreach name { out Hello $name } -> format json 223 [ 224 "Hello Tom", 225 "Hello Dick", 226 "Hello Sally" 227 ] 228 ``` 229 230 ## See Also 231 232 * [`a` (mkarray)](../commands/a.md): 233 A sophisticated yet simple way to build an array or list 234 * [`break`](../commands/break.md): 235 Terminate execution of a block within your processes scope 236 * [`foreach`](../commands/foreach.md): 237 Iterate through an array 238 * [`formap`](../commands/formap.md): 239 Iterate through a map or other collection of data 240 * [`if`](../commands/if.md): 241 Conditional statement to execute different blocks of code depending on the result of the condition 242 * [`ja` (mkarray)](../commands/ja.md): 243 A sophisticated yet simply way to build a JSON array 244 * [`let`](../commands/let.md): 245 Evaluate a mathematical function and assign to variable (deprecated) 246 * [`set`](../commands/set.md): 247 Define a local variable and set it's value 248 * [`while`](../commands/while.md): 249 Loop until condition false 250 251 <hr/> 252 253 This document was generated from [builtins/core/structs/for_doc.yaml](https://github.com/lmorg/murex/blob/master/builtins/core/structs/for_doc.yaml).