Newer
Older
[](https://travis-ci.org/redox-os/ion)
[](./LICENSE)
[](https://coveralls.io/github/redox-os/ion?branch=master)
[](https://crates.io/crates/ion-shell)
Ion is a shell for UNIX platforms, and is the default shell in Redox. It is still a work in progress, but much of the
core functionality is complete. Features below:
- [x] Shell Expansion
- [x] Flow Control
- [x] Aliases
- [x] Variables (**$variable**)
- [x] Substrings for Variables
- [x] Array Expressions (**[]**)
- [x] Array-based Command Substitution (**@[]**)
- [x] String-based Command Substitution (**$()**)
- [x] Array Methods (**@split(var, ' ')**)
- [x] String Methods (**$join(array, ', ')**)
- [ ] Maps
- [x] For Loops
- [ ] Foreach Loops
- [x] While Loops
- [x] If Conditionals
- [x] Piping Stdout/Stderr
- [x] Redirecting Stdout/Stderr
- [ ] Piping Builtins & Functions
- [x] **&&** and **||** Conditionals
- [x] Background Jobs
- [ ] Background Jobs Control
- [ ] Signal Handling
- [ ] Syntax Highlighting
- [x] Multiline Comments and Commands
- [ ] Multiline Editing
- [x] Tab Completion (Needs Improvements)
- [ ] Syntax for Color Handling
- [ ] Unescape specific character combinations, such as '\n' and '\t'
- [ ] Builtin Plugins
- [ ] Prompt Plugins
## Shell Syntax
### Defining Variables
The `let` keyword is utilized to create local variables within the shell. The `export` keyword performs
a similar action, only setting the variable globally as an environment variable for the operating system.
```ion
let git_branch = $(git rev-parse --abbrev-ref HEAD ^> /dev/null)
```
If the command is executed without any arguments, it will simply list all available variables.
Variables may be called with the **$** sigil, where the value that follows may be a local or global value.
They may also be optionally defined using a braced syntax, which is useful in the event that you need the value
integrated alongside other characters that do not terminate the variable parsing.
```ion
let a = one
let b = two
echo $A:$B
echo ${A}s and ${B}s
```
### Substrings from Variables
Ion natively supports splitting supplied strings by graphemes using the same slicing syntax for arrays:
```ion
$ let string = "one two three"
$ echo $string[0]
o
$ echo $string[..3]
one
$ echo $string[4..7]
two
$ echo $string[8..]
three
```
### Dropping Variables
To drop a value from the shell, the `drop` keyword may be used:
```ion
drop git_branch
```
### Variable Arithmetic
The `let` command also supports basic arithmetic.
```ion
let a = 1
echo $a
let a += 4
echo $a
let a *= 10
echo $a
let a /= 2
echo $a
let a -= 5
echo $a
```
### Export
The `export` command works similarly to the `let` command, but instead of defining a local variable, it defines a
global variable that other processes can access.
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
```ion
export PATH = "~/.cargo/bin:${PATH}"
```
### Export Arithmetic
The `export` command also supports basic arithmetic.
```ion
export a = 1
echo $a
export a += 4
echo $a
export a *= 10
echo $a
export a /= 2
echo $a
export a -= 5
echo $a
```
### Aliases
The `alias` command is used to set an alias for running other commands under a different name. The most common usages of the `alias` keyword are to shorten the keystrokes required to run a command and it's specific arguments, and to rename a command to something more familiar.
```ion
alias ls = 'exa'
```
If the command is executed without any arguments, it will simply list all available aliases.
The `unalias` command performs the reverse of `alias` in that it drops the value from existence.
```ion
unalias ls
```
### Brace Expansion
Brace expansions are used to create permutations of a given input. In addition to simple permutations, Ion supports
brace ranges and nested branches.
```ion
echo abc{3..1}def{1..3,a..c}
echo ghi{one{a,b,c},two{d,e,f}}
```
### Defining Arrays
Arrays can be create with the let keyword when the supplied expression evaluates to a vector of values:
The basic syntax for creating an array of values is to wrap the values inbetween **[]** characters. The syntax within
will be evaluated into a flat-mapped vector, and the result can therefor be stored as an array.
```ion
let array = [ one two 'three four' ]
```
One particular use case for arrays is setting command arguments
```ion
let lsflags = [ -l -a ]
ls @lsflags
```
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#### Braces Create Arrays
Brace expansions actually create a vector of values under the hood, and thus they can be used to create an array.
```ion
let braced_array = {down,up}vote
```
#### Array-based Command Substitution
Whereas the standard command substitution syntax will create a single string from the output, this variant will create
a whitespace-delimited vector of values from the output of the command.
```ion
let word_split_process = @[echo one two three]
```
### Using Arrays
Arrays may be called with the **@** sigil, which works identical to the variable syntax:
```ion
echo @braced_array
echo @{braced_array}
```
Arrays may also be sliced when an index or index range is supplied:
#### Slice by Index
Slicing by an index will take a string from an array:
echo @array[1]
echo @array[2]
echo [ 1 2 3 ][0]
echo [ 1 2 3 ][1]
echo [ 1 2 3 ][2]
echo @[echo 1 2 3][0]
echo @[echo 1 2 3][1]
echo @[echo 1 2 3][2]
```
#### Slice by Range
Slicing by range will take a subsection of an array as a new array:
```ion
let array = [ 1 2 3 4 5 ]
echo @array[0..1]
echo @array[0...1]
echo @array[..3]
echo @array[3..]
echo @array[..]
### Methods
There are two types of methods -- string-based and array-based methods. The type that a method returns is denoted
by the sigil that is used to invoke the method. Currently, there are only two supported methods: **$join()** and
**@split**.
```ion
let results = [ 1 2 3 4 5]
echo $join(results) @join # Both of these effectively do the same thing
echo $join(results, ', ') # You may provide a custom pattern instead
let line = "one two three four five"
echo @split(line) # Splits a line by whitespace
let row = "one,two,three,four,five"
echo @split(row, ',') # Splits by commas
```
### Substring Slicing on String Methods
```ion
echo $join(array)[3..6]
```
### Array Slicing on Array Methods
```ion
let cpu_model = $(grep "model name" /proc/cpuinfo | head -1)
echo @split(cpu_model)[3..5]
```
### Commands
Commands may be written line by line or altogether on the same line with semicolons separating them.
```ion
command arg1 arg2 arg3
command arg1 arg2 arg3
command arg1 arg2 arg3; command arg1 arg2 arg3; command arg1 arg2 arg3
```
The pipe (`|`) and redirect (`>`) operators are used for manipulating the standard output.
```ion
command arg1 | other_command | another_command arg2
command arg1 > file
```
### Piping & Redirecting Standard Error
The `^|` and `^>` operators are used for manipulating the standard error.
```ion
command arg1 ^> file
```
### Piping & Redirecting Both Standard Output & Standard Error
The `&|` and `&>` operators are used for manipulating both the standard output and error.
```ion
command arg1 &| other_command # Not supported yet
command arg1 &> file
```
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
### Conditional Operators
The Ion shell supports the `&&` and `||` operators in the same manner as the Bash shell. The `&&` operator
executes the following command if the previous command exited with a successful exit status. The `||`
operator performs the reverse -- executing if the previous command exited in failure.
```ion
test -e .git && echo Git directory exists || echo Git directory does not exist
```
### If Conditions
It is also possible to perform more advanced conditional expressions using the `if`, `else if`, and `else` keywords.
```ion
let a = 5;
if test $a -lt 5
echo "a < 5"
else if test $a -eq 5
echo "a == 5"
else
echo "a > 5"
end
```
### While Loops
While loops will evaluate a supplied expression for each iteration and execute all the contained statements if it
evaluates to a successful exit status.
```ion
let a = 1
while test $a -lt 100
echo $a
let a += 1
end
```
### For Loops
For loops, on the other hand, will take a variable followed by a list of values or a range expression, and
iterate through all contained statements until all values have been exhausted. If the variable is `_`, it
will be ignored. Take note that quoting rules are reversed for for loops, and values from string-based command
substitutions are split by lines.
```ion
# Obtaining Values From a Subshell
for a in $(seq 1 10)
echo $a
end
# Values Provided Directly
for a in 1 2 3 4 5
echo $a
end
# Exclusive Range
for a in 1..11
echo $a
end
# Inclusive Range
for a in 1...10
echo $a
end
# Ignore Value
for _ in 1..10
do_something
end
# Brace Ranges
for a in {1..10}
echo $a
end
# Globbing
for a in *
echo $a
end
### Command Substitution
Command substitution allows the user to execute commands within a subshell, and have the data written to standard
output used as the substitution for the expansion. There are two methods of performing command substitution: string and
array-based command substitution. String-based command substitutions are the standard, and they are created by wrapping
the external command between **$(** and **)**. Array-based command substitution is denoted by wrapping the command
between **@[** and **]**. The first merely captures the result as a single string, precisely as it was written, while
the second splits the data recieved into words delimited by whitespaces.
Try comparing the following:
```ion
for i in $(echo 1 2 3)
echo $i
end
```
```ion
for i in @[echo 1 2 3]
echo $i
end
```
### Slicing String-Based Command Substitutions
You may slice the string returned to obtain its substring:
```ion
echo $(echo one two three)[..3]
```
### Slicing Array-Based Command Substitutions
You may slice the array returned to obtained a specific set of elements:
```ion
echo @[grep "model name" /proc/cpuinfo | head -1][3..5]
```
### Functions
Functions in the Ion shell are defined with a name along with a set of variables. The function
will check if the correct number of arguments were supplied and execute if all arguments
were given.
```ion
fn fib n
if test $n -le 1
echo $n
else
let output = 1
let previous = 1
let temp = $output
let output += $previous
let previous = $temp
end
echo $output
end
end
for i in 1..20
fib $i
end