1 | # Command language
|
2 |
|
3 | ## Simple commands
|
4 |
|
5 | ### variable declaration and mutation
|
6 |
|
7 | # Declaring a variable does NOT looks like this:
|
8 | # Variable="Some string" => name=val isn't allowed when shopt 'parse_equals' is on.
|
9 | # Hint: add 'env' before it, or spaces around =
|
10 |
|
11 | # Nor like this
|
12 | # Variable = "Some string" # => same error
|
13 |
|
14 | # this is the preferred way
|
15 | # no need for capitalization like in bash
|
16 | var variable = "Some string"
|
17 |
|
18 | # also valid but not idomatic
|
19 | set variable = "Another string"
|
20 |
|
21 | # const to declare a constant
|
22 | const immutable = "definitive"
|
23 |
|
24 | # this will not work
|
25 | # set immutable = "not so sure" => Can't modify constant 'immutable'
|
26 |
|
27 | # mutate a variable with setvar
|
28 | var new = "a brave new world"
|
29 | setvar new = "perhaps it's already here"
|
30 | echo $new
|
31 |
|
32 | # setglobal will create or mutate a global variable
|
33 | setglobal the_answer = 42
|
34 | echo $the_answer
|
35 |
|
36 | # there are more ways to set variable by passing them
|
37 | # to procs. This will be expanded in the procs section
|
38 |
|
39 | ### Variable substitution
|
40 |
|
41 | var regular_string = "I am just a normal string"
|
42 | echo $regular_string # quotes not needed
|
43 | #### if you want to do string interpolation
|
44 | echo "$regular_string and $regular_string"
|
45 | #### you need to do it another way if you want to substitute before a _
|
46 | # this will not work "$regular_string_"
|
47 | # as it will look for the regular_string_ variable
|
48 | echo "${regular_string}_" # but this will
|
49 |
|
50 | ### Parameter expansion works just like in bash
|
51 | var some_string = "I am some string"
|
52 | echo ${some_string/another/some} # => I am another string
|
53 |
|
54 | ### Strings
|
55 |
|
56 | # this will not work
|
57 | # echo "\n" => Invalid char escape in double quoted string
|
58 | # this prints the characters
|
59 | echo '\n'
|
60 | # use $ to print a new line
|
61 | echo $'\n'
|
62 |
|
63 | # unicode works like this
|
64 | # var unicode = j"mu = \u{3bc}"
|
65 | # echo $unicode
|
66 |
|
67 | # but not like this
|
68 | # var unicode = 'mu = \u{3bc}' => Strings with backslashes should look like r'\n', c'\n' or $'\n'
|
69 |
|
70 | ### builtins
|
71 |
|
72 | #### echo
|
73 | # takes at most 1 argument and prints to stdout
|
74 | echo "Hello world!" # => Hello world!
|
75 |
|
76 | #### write
|
77 | # write outputs to stdout
|
78 | # write has a -- separator to not confuse command line arguments and what you want to print
|
79 | var i_am_a_string = "I'm just a string"
|
80 | write -- $i_am_a_string
|
81 | # if you have a string with a newline in it
|
82 | var i_have_a_newline = $'it\'s true I really do \n'
|
83 | # write works well with it, unlike bash's printf
|
84 | write -- $i_have_a_newline
|
85 | # you can print the content without the newline with -n
|
86 | write -n -- $i_have_a_newline
|
87 |
|
88 | #### test
|
89 | # test has been improved to be a little less crytic
|
90 |
|
91 | # test if something is a directory
|
92 | test --dir /tmp || echo "Not a dir"
|
93 | test -d /tmp # still works but less readable
|
94 |
|
95 | # test if something is a file
|
96 | test --file /tmp/maybe_a_file || echo "Not a file"
|
97 |
|
98 | ### Procs
|
99 |
|
100 | ### think of procs as a better version of bash's functions
|
101 | ### use proc for abstraction
|
102 | proc abstract() {
|
103 | echo "I'm an abstraction"
|
104 | }
|
105 |
|
106 | ### and call it without brackets
|
107 | abstract
|
108 |
|
109 | ### proc can't access variables they are not given as params
|
110 | ### proc print_variable() {
|
111 | ### echo $some_not_given_variable
|
112 | ### }
|
113 | ### print_variable
|
114 | ### fatal: Undefined variable 'some_not_given_variable'
|
115 |
|
116 | proc print_variable(passed_variable) {
|
117 | echo $passed_variable
|
118 | }
|
119 |
|
120 | ### call procs with arguments without brackets
|
121 | var variable_to_pass = "I'm passed"
|
122 | print_variable $variable_to_pass
|
123 |
|
124 | # If you're going to use a shell function or proc in a condition, wrap it with 'try'
|
125 | # to avoid a strict_errexit error
|
126 | proc myproc {
|
127 | echo hi
|
128 | return 1
|
129 | }
|
130 |
|
131 | try {
|
132 | myproc
|
133 | }
|
134 | if (_status !== 0) {
|
135 | echo failure
|
136 | }
|
137 |
|
138 | ### external commands
|
139 |
|
140 | ### Ruby like blocks
|
141 |
|
142 | ## Redirects
|
143 |
|
144 | ## Pipelines
|
145 |
|
146 | ## Control flow
|
147 |
|
148 | ### general
|
149 |
|
150 | ### use command substitution to assign the result of a command to a variable
|
151 | var year = $(date -u +"%Y")
|
152 | echo $year
|
153 |
|
154 | # a failure will exit immediately
|
155 | # var year = $(date --wrong-flag +"%Y") => date: illegal option -- -
|
156 | # usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
|
157 | # [-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
|
158 | # var year = $(date --wrong-flag "%Y")
|
159 | # ^~
|
160 | # ./tour.sh:38: fatal: Command sub exited with status 1 (command.Simple)
|
161 |
|
162 |
|
163 | ### if
|
164 |
|
165 | # if works just like you would expect
|
166 |
|
167 | if true {
|
168 | echo "Here I am!"
|
169 | } else {
|
170 | echo "I'll never be"
|
171 | }
|
172 |
|
173 | # However be careful, brackets have a special meaning
|
174 | # those are for conditionals, you won't be able to
|
175 | # run functions inside those
|
176 | proc is_it_true() {
|
177 | false
|
178 | }
|
179 | # this won't work
|
180 | # if (! is_it_true) {
|
181 | # echo "could be anything really"
|
182 | # }
|
183 | # Syntax error in expression (near Id.Expr_Bang)
|
184 | # to make it work you have to 'try' the proc
|
185 | # and remove the brackets
|
186 |
|
187 | try { is_it_true }
|
188 | if (_status !== 0) {
|
189 | echo "could be anything really"
|
190 | }
|
191 |
|
192 | # an error in a proc will print
|
193 | proc err_today() {
|
194 | date --wrong-flag
|
195 | }
|
196 |
|
197 | try {
|
198 | err_today
|
199 | echo "will never be executed"
|
200 | }
|
201 | if (_status !== 0) {
|
202 | # this will also print the proc error
|
203 | # date: illegal option -- -
|
204 | # usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
|
205 | # [-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
|
206 | echo "there was an error"
|
207 | }
|
208 |
|
209 | ### case
|
210 |
|
211 | ### for
|
212 |
|
213 | ### while
|
214 |
|
215 | ## fork and wait
|
216 |
|
217 | ## Expression language
|
218 |
|
219 | ### Eggex
|
220 |
|
221 | #### matching happens with eggexes, which are a different take on regex
|
222 | #### you can use
|
223 | #### digit => to match numbers
|
224 | #### word => to match any character that is not a space
|
225 | #### space => to match all the non word characters (tab, newline...)
|
226 | #### dot => to match any character
|
227 |
|
228 | var s = '123'
|
229 | if (s ~ /digit+/) {
|
230 | echo 'number'
|
231 | }
|
232 |
|
233 | #### extract a submatch with < >
|
234 | #### if ($(date -u +"%Y-%m-%d") ~ /< digit{4} :year> '-' <digit{2} :month>!word<digit{2} :day>/) {
|
235 | if ($(date -u +"%Y-%m-%d") ~ /<capture digit{4} as year> '-' <capture digit{2} as month> '-' <capture digit{2} as day>/) {
|
236 | # extract a match by number
|
237 | const complete_match = _match(0)
|
238 | const group_match = _match(1)
|
239 | echo $complete_match
|
240 | echo $group_match
|
241 | }
|