-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path0-basics.sh
More file actions
1418 lines (1069 loc) · 36.7 KB
/
0-basics.sh
File metadata and controls
1418 lines (1069 loc) · 36.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/sh
. .lib/shell-compat-test.sh
_DURATION=20
_LSN_VERSION=1.0.0
# Put tutorial library files into $PATH if they are not already added
if [[ -d "$PWD/.lib" && ":$PATH:" != *":$PWD/.lib:"* ]]; then
PATH=$PWD/.lib:$PATH
fi
source ansi-terminal-ctl.sh
source progress.sh
if [[ -n $_TUTR ]]; then
source damlev.sh
source generic-error.sh
source noop.sh
source platform.sh
_Google() { echo ${_B}G${_R}o${_Y}o${_B}g${_G}l${_R}e${_z}; }
_code() { (( $# == 0 )) && echo $(cyn code) || echo $(cyn "$*"); }
_err() { (( $# == 0 )) && echo $(red error) || echo $(red "$*"); }
fi
_make_files() {
cat <<-TEXT > "$_BASE/textfile.txt"
_ _ _ _ __ __ _ _ _
| | | | ___| | | ___ \\ \\ / /__ _ __| | __| | |
| |_| |/ _ \\ | |/ _ \\ \\ \\ /\\ / / _ \\| '__| |/ _\` | |
| _ | __/ | | (_) | \\ V V / (_) | | | | (_| |_|
|_| |_|\\___|_|_|\\___( ) \\_/\\_/ \\___/|_| |_|\\__,_(_)
|/
Welcome to the GAS command shell tutorial!
This tutor has been adapted from the CS1440 Shell Tutor assignment.
Credit it for its creation and design go to Erik Falor, Jaxton Winder
and other TAs and CS students who assisted Erik in its design and upkeep.
Credit for changes made repurposing this assignment for the GAS team goes
to Joshua Hessing.
It is my hope that this tutorial series helps you to quickly become
comfortable in the Unix command line environment.
TEXT
cat <<-TEXT > "$_BASE/markdown.md"
# This is a Markdown file
This is a text file written in the **Markdown** format.
Markdown is a text-to-HTML conversion tool for web writers. Markdown allows
you to write using an easy-to-read, easy-to-write plain text format, then
convert it to structurally valid XHTML (or HTML).
Markdown was created by John Gruber and is documented on his website
[Daring Fireball](https://daringfireball.net/projects/markdown/).
TEXT
cat <<-'TEXT' > "$_BASE/.hidden"
YOU FOUND THE IMPOSTER!
____
_| ___\!!
| |(____) /`-.__
|_| \ | |__|
|__/\__| \.-`\|
____ REPORT
__ /___ |_ _____
_||_ _ (____)| | \ /
| _ |_| | _ |_| \USE/
|__|__| |__|__| \ /
File names starting with a dot '.' are hidden by commands like 'ls' by
default. This was due to a bug in 'ls' from the early days of Unix.
Unix users now use this bug to clean up their home directories. Instead
of showing dozens of config files, 'ls' keeps them out of sight. Today,
these hidden config files are called 'dotfiles'.
This is an example of a "bug" becoming a feature. So, don't worry about
making mistakes; they're just unexpected features!
https://linux-audit.com/linux-history-how-dot-files-became-hidden-files/
TEXT
cat <<-TEXT > "$_BASE/top.secret"
You should not be able to read this message because you lack read
permission on this file.
If you are reading this message, please report it as a bug.
(Unless you used a command like 'sudo';
in that case you're missing the point of this exercise.)
TEXT
case $(uname -s) in
*MINGW*)
icacls "$_BASE/top.secret" //deny "$USERNAME:(d)"
;;
*)
chmod -r "$_BASE/top.secret"
;;
esac
return 0
}
_make_corrupt_terminal() {
local esc=$'\x1b'
cat <<-TEXT > "$_BASE/corrupt_terminal"
Using 'cat' on this file will garble your screen. Use with caution.
Set reverse video mode ${esc}[?5h
DEC screen alignment test - fills screen with E's ${esc}#8
Pretty wild, huh?
You can still run commands when the $(_term) is in this state.
You just can't read the output.
Try running 'ls', 'echo hello world', and 'cat textfile.txt'.
Use 'reset' to restore your $(_term) when you're done. ${esc}(0
TEXT
}
setup() {
source screen-size.sh 80 30
export _BASE="$PWD/lesson0"
[[ -d "$_BASE" ]] && rm -rf "$_BASE"
mkdir -p "$_BASE"
_make_files
}
prologue() {
[[ -z $DEBUG ]] && clear
echo
cat <<-PROLOGUE
$(_tutr_progress)
Shell Lesson #0: Unix Shell Basics
In this lesson you will learn about
* Using the Unix command line interface (CLI)
* Commands and arguments
* Hidden files
* The difference between the $(_shell \'shell\') and the $(_term \'terminal\')
* How to clear and reset the $(_term)
* Cancelling a runaway command
* Understanding messages and recovering from errors
This lesson takes around $_DURATION minutes.
PROLOGUE
_tutr_pressenter
}
# Introduce the 'tutor' command
tutor_hint_prologue() {
local PLUS=$'\x1b[1;32m+\x1b[0m'
cat <<-:
Before we begin, you need to know how this thing works.
I'll give you things to do, and you'll do your best to do them. As you
work, the progress bar above your prompt turns from $(red red) to $(grn green).
There are ${#_STEPS[@]} things to do in this lesson (it only looks like $((${#_STEPS[@]} - 1)) because
I count from zero). After you have done enough things you'll win, which
improves your self-esteem.
You do things in the $(_shell) by running commands. When I show you a
command I highlight it in green, like this:
$(cmd tutor hint)
Now, if you ever find yourself in a situation where you don't know what
thing to do, use the $(cmd tutor hint) command.
Why don't you try it right now? Run $(cmd tutor hint) to earn your first $PLUS.
:
}
tutor_hint_test() {
_tutr_generic_test -c tutor -a hint
}
tutor_hint_hint() {
_tutr_generic_hint $1 tutor
echo
echo "The command will look like this"
echo " $(cmd tutor hint)"
}
tutor_hint_epilogue() {
cat <<-:
Deja vu always creeps me out OwO
:
_tutr_pressenter
cat <<-:
The $(cmd tutor hint) command redisplays your marching orders.
This command will come in handy, so $(bld "remember it!")
When I (the tutor) say something to you, it will start with "$(grn Tutor):".
This lets you distinguish my messages from output produced by the other
commands you will run.
${_W} .0000. .0000. ${_z}
${_W},000000, ,000000,${_z}
$(cyn "Do not skim; read everything!") ${_W}00 0000 00 0000${_z}
${_W}'000000' '000000'${_z}
${_W} '0000' '0000' ${_z}
Otherwise, you $(bld will) get lost.
:
_tutr_pressenter
cat <<-:
After your progress bar is filled up, I will make some concluding
remarks and then record your completion. If you close the tutorial
$(bld before) it quits on its own (say, by clicking the $(red close) button up in the
corner of this window), this record is not made and you will need to do
the lesson $(bld all over again).
This is a map of the tutorial:
+-- You are here
|
$(_tutr_progress)
The $(red red) boxes are lessons that are not complete.
They turn $(blu blue) when you finish them.
You can safely close this window the next time you see this map.
:
_tutr_pressenter
cat <<-:
If these words are too hard to read, try changing the font size.
The exact method depends on your software, but these instructions
may do the trick.
:
if [[ "$TERM_PROGRAM" == Apple_Terminal || $_PLAT == Apple ]]; then
cat <<-:
* $(kbd "Command+=") (Command equal sign) makes text $(bld bigger) (it is listed as
$(kbd Command plus), but you do not need to hold $(kbd Shift) for it to work)
* $(kbd "Command+-") (Command minus) makes text $(bld smaller)
* Find the settings labeled $(bld Bigger) and $(bld Smaller) in the $(bld View) menu
:
elif [[ $_PLAT == MINGW && "$TERM_PROGRAM" == mintty ]]; then
cat <<-:
* $(kbd "Ctrl+=") (Control equal sign) makes text $(bld bigger) (it is listed as
$(kbd Control plus), but you do not need to hold $(kbd Shift) for it to work)
* $(kbd "Ctrl+-") (Control minus) makes text $(bld smaller)
* Right click the window's title bar, choose $(bld Options), select $(bld Text) in the
tree on the left, then pick a larger font. Click $(bld Save) to make your
choice permanent.
:
elif [[ $_PLAT == MINGW && -n "$_WT_SESSION" ]]; then
cat <<-:
* $(kbd "Ctrl+=") (Control equal sign) makes text $(bld bigger) (it is listed as
$(kbd Control plus), but you do not need to hold $(kbd Shift) for it to work)
* $(kbd "Ctrl+-") (Control minus) makes text $(bld smaller)
* Open the Settings page by pressing $(kbd "Ctrl+,") (Control comma), or by clicking
the chevron symbol in the tab bar (it looks like a "$(bld V)"), then
go to $(bld Defaults) under the $(bld Profiles) section in the left menu bar, then
open $(bld Appearance) under the $(bld Additional) Settings section.
Under $(bld Text) adjust the $(bld Font size), then click $(bld Save) to make your choice permanent.
:
else
cat <<-:
* $(kbd "Ctrl+=") (Control equal sign) makes text $(bld bigger) (it is listed as
$(kbd Control plus), but you do not need to hold $(kbd Shift) for it to work)
* $(kbd "Ctrl+-") (Control minus) makes text $(bld smaller)
* Find the font settings in the $(bld Edit) or $(bld View) menu
:
fi
cat <<-:
If all else fails, you can $(_Google) it.
:
_tutr_pressenter
}
tutor_bug_prologue() {
cat <<-:
One of the things that you will learn on the team is that it is very
difficult to write good, correct code. This tutorial is no exception.
I don't want to alarm you, but it is quite likely that you will uncover
a bug in this tutorial. It might be a crash, a glitch, or even a
"mis-speled" word.
When that happens to you, $(mgn "DON'T PANIC!") Keep a level head and help me
fix it. Just remember to run this command:
$(cmd tutor bug)
I want you to try this now. The message you are about to see will
apologize for a bug and ask you to send me an email. $(bld IT IS NOT A BUG!)
Please don't send me an email now! This is just a dry-run.
:
}
tutor_bug_test() {
_tutr_generic_test -c tutor -a bug
}
tutor_bug_hint() {
if [[ $1 == $MISSPELD_CMD ]]; then
_tutr_generic_hint $1 tutor
fi
cat <<-:
Let's try that again.
The command to run looks like this:
$(cmd tutor bug)
:
}
tutor_bug_epilogue() {
_tutr_pressenter
cat <<-:
When a $(bld real) problem occurs I want you to run $(cmd tutor bug), scroll up in the
window and copy the text leading up to your problem all the way down
through $(cmd tutor bug)'s output. And by "$(cyn copy the text)" I don't mean "take a
screenshot". Use your mouse to highlight the words, then open the Edit
menu and click "Copy".
By the way, you can quit this tutorial at any time by running $(cmd exit) or
$(cmd tutor quit). But the only way to win is to stick with it to the end.
Now you're $(bld really) ready to begin!
:
_tutr_pressenter
}
hello_world_prologue() {
cat <<-:
${_W}oooooooooooooooooooooooooooooo${_Z}
${_W}8 888${_Z}
${_W}8 ${_g}ooooooooooooooooooooooo ${_W}888${_Z} The Unix Command Line Interface (CLI)
${_W}8 ${_g}88888888888888888888888 ${_W}888${_Z} lets you talk to your computer with a
${_W}8 ${_g}8888888888888888888888P ${_W}888${_Z} simple programming language. This
${_W}8 ${_g}8888888888888888888P" ${_W}888${_Z} environment is called the $(_shell Shell)
${_W}8 ${_g}8888888888888888P" ${_W}888${_Z}
${_W}8 ${_g}8888888888888P" ${_W}888${_Z} In contrast to other languages you have
${_W}8 ${_g}8888888888P" ${_W}888${_Z} used, the Unix $(_shell) prioritizes
${_W}8 ${_g}8888888P" ${_W}888${_Z} $(bld interactivity) above all else.
${_W}8 ${_g}8888P" ${_W}888${_Z}
${_W}8 ${_g}8P" ${_W}888${_Z} Thus, it was intentionally designed
${_W}8 .od888888888888888888${_R}c${_G}g${_B}mm${_W}888${_Z} to be easy to type:
${_W}888888888888888888888888888888${_Z}
${_W} ${_Z} * Commands have $(cyn short names)
${_W} oooooooooooooooooooooo ${_Z} * $(cyn Minimal) punctuation is required
${_W} d${_w} ..oood8${_W}b ${_Z} * Only $(cyn one type) of data (string)
${_W} d${_w} ..oood888888888${_W}b ${_Z}
${_W} d${_w} ..oood88888888888888888${_W}b ${_Z}
${_W}dood8888888888888888888888888b${_Z}
:
_tutr_pressenter
cat <<-:
Begin by saying "Hello World" the command-line way.
In $(_py) you would write:
$(_code 'print("Hello, World")')
But here in the $(_shell) it looks like this:
$(cmd echo Hello, World)
Notice that the arguments $(cmd Hello,) and $(cmd World) are not quoted.
Run this command now.
:
}
hello_world_test() {
_PREV1=${_CMD[1]}
_PREV2=${_CMD[2]}
[[ $( echo "${_CMD[@]}" | tr A-Z a-z | tr -d ,) == "echo hello world" ]] && return 0
_tutr_damlev "${_CMD[0]}" "echo" 2 && return $MISSPELD_CMD
[[ $_SH = Zsh && ${_CMD[0]} = print ]] && return 99
[[ ${_CMD[0]} != echo ]] && return $WRONG_CMD
[[ ${#_CMD[@]} -lt 3 ]] && return $TOO_FEW_ARGS
[[ ${#_CMD[@]} -gt 3 ]] && return $TOO_MANY_ARGS
return $WRONG_ARGS
}
hello_world_hint() {
case $1 in
99)
cat <<-:
Because you're using the $(bld Zsh) $(_shell), you actually have a
command called $(cmd print) that is equivalent to $(cmd echo).
Because most students use the $(bld Bash) $(_shell), I encourage $(cmd echo)
for consistency's sake.
:
;;
*)
_tutr_generic_hint $1 echo "$_BASE"
;;
esac
cat <<-:
Run $(cmd echo Hello, World)
:
}
hello_world_epilogue() {
_tutr_pressenter
echo
if [[ "echo Hello, World" != ${_CMD[@]} ]]; then
cat <<-:
Eh, "$(cmd ${_CMD[@]})" is close enough for now...
In the $(_shell), as with $(_py), details like CASE and "punctuation"
matter. Be diligent and follow instructions $(bld exactly)!
:
_tutr_pressenter
echo
fi
cat <<-:
$(_shell Shell) commands can take arguments, just like functions in $(_py).
The strings $(cyn "'$_PREV1'") and $(cyn "'$_PREV2'") were arguments to $(cmd echo).
$(_shell Shell) commands follow this syntax:
$(cmd 'command [argument ...]')
The square brackets surrounding $(cmd 'argument...') in the example indicate
an optional portion. The ellipsis ($(cmd ...)) means that there may be more
arguments beyond the first one. All together, this example means
"$(cyn \'command\' takes zero or more arguments)".
Unlike $(_py) and Java, parentheses do not surround the argument list of
$(_shell) commands. Spaces separate arguments from each other instead of
commas. It $(bld does not) matter how many spaces are present. One, two or
twenty - it's all the same.
:
_tutr_pressenter
cat <<-:
In the $(_shell) $(bld everything) is regarded as a string - even numbers. This is
why you don't need quote marks around the words $(cyn "'$_PREV1'") and $(cyn "'$_PREV2'").
The comma following $(cyn "'Hello,'") in the command
$(cmd echo Hello, World)
isn't special; it is just part of the string $(cyn "'Hello,'").
Now, there are cases where quote marks are mandatory; this just isn't
one of them. Of course, you could use quote marks if you really wanted
to, like this:
$(cmd echo \"Hello, World\")
:
_tutr_pressenter
}
echo_no_args_prologue() {
cat <<-:
Part of studying $(_py) is learning which $(_code functions) can be used and
how to call them.
The Unix $(_shell) is similar. Here you learn what $(cmd commands) exist and how
to run them.
$(cmd echo) is the $(_shell "shell's") equivalent to $(_py "Python's") $(_code 'print()') function. Just
like $(_code 'print()'), $(cmd echo) takes any number of arguments. Zero, one, two,
or twenty; it's all good.
The $(cmd echo) command has this syntax:
$(cmd 'echo [WORD...]')
This means that $(cmd echo) can take zero or more $(cmd WORDs) as arguments.
Run $(cmd echo) again, but without any arguments.
:
}
echo_no_args_test() {
_tutr_generic_test -c echo
}
echo_no_args_hint() {
_tutr_generic_hint $1 echo "$_BASE"
cat <<-:
Simply run $(cmd echo) with no arguments to see what happens.
:
}
echo_no_args_epilogue() {
_tutr_pressenter
cat <<-:
Just like $(_code 'print()'), running $(cmd echo) with no arguments outputs a blank line.
Arguments are passed into commands as a $(bld list of strings). It is up to
each command to decide how many arguments to take, what order they
should appear, and what each should mean.
Some commands, like $(cmd echo), are happy with $(bld any) number of arguments.
Other commands are picky about their arguments. Often, they will
display a helpful error message when given invalid input.
In the next lesson you will learn how to read the instruction manual for
each command. This will help you learn what commands exist and how to
use them.
:
_tutr_pressenter
cat <<-:
You will encounter nearly two dozen commands
throughout the course of this tutorial. ${_W}(\\
It is a lot to absorb! ${_W}\\${_y}'${_W}\ ${_z} __________
${_W} \\${_y}'${_W}\ ${_z}()_________)
Students have reported learning these commands ${_W} / ${_y}'${_W}| ${_z} \ ${_B}Make a${_z} \\
more quickly by keeping notes as they work ${_W} \ ${_y}'${_W}/ ${_z} \ ${_B} Note!${_z} \\
through the tutorial. ${_y} \ ${_z} \__________\\
${_B} ==). ${_z} ()__________)
Be sure to record the command's $(red name), ${_B} (__)${_z}
its $(blu purpose), and what $(grn arguments) it takes.
After a few weeks you will not need these notes to use the $(_shell).
But until then, they are invaluable!
:
_tutr_pressenter
}
ls_prologue() {
cat <<-:
The $(cmd ls) command lists files.
Run $(cmd ls) to see what files are here.
:
}
ls_test() {
[[ $PWD != "$_BASE" ]] && return $WRONG_PWD
[[ ( ${_CMD[0]} == ls || ${_CMD[0]} == dir ) && ${#_CMD[@]} -ne 1 ]] && return $TOO_MANY_ARGS
[[ ${_CMD[@]} == ls || ${_CMD[@]} == dir ]] && return 0
_tutr_damlev "${_CMD[0]}" ls 1 && return $MISSPELD_CMD
[[ ( ${_CMD[0]} != ls && ${_CMD[0]} != dir ) ]] && return $WRONG_CMD
}
ls_hint() {
_tutr_generic_hint $1 ls "$_BASE"
cat <<-:
Run $(cmd ls) with no arguments to list the files that are here
:
}
ls_epilogue() {
if [[ ${_CMD[@]} == dir ]]; then
_tutr_pressenter
cat <<-:
A Windows user, eh?
Unix also has a command called $(cmd dir), but it is not commonly used.
One extra letter is too much for lazy Unix-folk to type.
This tutorial will use $(cmd ls) from now on.
:
fi
_tutr_pressenter
cat <<-:
Remember, lines without $(grn Tutor): come from the commands you run.
$(cmd ls) revealed that there are $(bld three) files here. You will take a closer look
at each of these files throughout this tutorial.
:
_tutr_pressenter
}
## Generic test for the cat steps
# Usage: cat_GENERIC_test filename
cat_GENERIC_test() {
_CORRUPTED=99
[[ "$PWD" != "$_BASE" ]] && return $WRONG_PWD
if [[ ${_CMD[0]} == cat ]]; then
[[ ${#_CMD[@]} -eq 1 ]] && return $TOO_FEW_ARGS
[[ ${#_CMD[@]} -gt 2 ]] && return $TOO_MANY_ARGS
[[ ${_CMD[1]} == $1 ]] && return 0
[[ ${_CMD[1]} == corrupt_terminal ]] && return $_CORRUPTED
return $WRONG_ARGS
fi
_tutr_noop && return $NOOP
_tutr_generic_test -c cat -a $1
}
## Generic guidance for the cat steps
# Usage: cat_GENERIC_hint status_code filename
cat_GENERIC_hint() {
case $1 in
$NOOP)
return
;;
$_CORRUPTED)
reset
echo "It is not time for that file yet."
;;
$TOO_FEW_ARGS)
cat <<-:
$(bld "What just happened?")
Because you didn't tell $(cmd cat) which file to read, it started reading
you! If you typed any words and hit $(kbd Enter), they were duplicated on the
screen.
Remember that $(kbd Ctrl-C) (a.k.a. $(kbd ^C)) is your general purpose "get me out
of this program" tool. Try it any time a command gets stuck or freezes.
It usually works.
:
;;
$TOO_MANY_ARGS)
cat <<-:
You've figured out how to concatenate many files. Cool!
This will actually come in handy later on in the course.
But for now, I need you to only $(cmd cat) the one file I asked for.
Precision counts!
:
;;
*)
_tutr_generic_hint $1 cat "$_BASE"
;;
esac
if [[ -n "$2" ]]; then
cat <<-:
Use $(cmd cat) to print the contents of $(path $2) to the screen.
:
fi
cat <<-:
If it freezes, press $(kbd Ctrl-C) to return to the $(_shell) prompt.
:
}
cat_textfile_prologue() {
cat <<-:
You can read files in the $(_shell) with the $(cmd cat) command. Its name is short
for "$(bld Concatenate)". This program is meant to join several files into
one. It takes as arguments names of files and prints their contents,
one by one, onto the screen.
$(cmd 'cat [filename ...]')
Because it works fine with only one file, it has become the standard text
viewer in Unix.
One of the files here is called $(path textfile.txt). Print its contents
to the screen by running $(cmd cat) with the single argument $(path textfile.txt).
If $(cmd cat) gets stuck, press $(kbd Ctrl-C) to $(red cancel) it and try again.
:
}
cat_textfile_test() {
cat_GENERIC_test textfile.txt
}
cat_textfile_hint() {
cat_GENERIC_hint $1 textfile.txt
}
cat_textfile_epilogue() {
_tutr_pressenter
}
echo_textfile_prologue() {
cat <<-:
So what's the difference between $(cmd cat) and $(cmd echo)?
* $(cmd cat) shows what's on the $(bld inside) of a file named as its argument
* $(cmd echo) just repeats its arguments $(bld verbatim)
Now that you've seen what $(cmd cat) does with the argument $(path textfile.txt), run
$(cmd echo textfile.txt)
to see this difference firsthand.
:
}
echo_textfile_test() {
_tutr_generic_test -c echo -a textfile.txt -d "$_BASE"
}
echo_textfile_hint() {
if [[ ${_CMD[@]} == "cat textfile.txt" ]]; then
cat <<-:
That's what I asked you to run last time!
:
fi
_tutr_generic_hint $1 echo "$_BASE"
cat <<-:
This time you need to $(cmd echo) the filename $(path textfile.txt)
:
}
echo_textfile_epilogue() {
_tutr_pressenter
cat <<-:
To recap:
* $(cmd echo) just repeats what it is told to say
* $(cmd cat) lets you see what is inside a file
* $(cmd ls) shows you which files are present
:
_tutr_pressenter
}
cat_markdown_prologue() {
cat <<-:
Unix doesn't put as much importance on file names as other operating
systems do. A name ending in $(path .txt) is not what makes a text file.
It's what's on the inside that counts.
One kind of file that you will use this semester is the Markdown file.
Markdown files are just text files with names ending in $(path .md).
$(cmd cat) is a great tool for reading these files.
Give the name of the Markdown file as an argument to $(cmd cat).
You can use $(cmd ls) to remind yourself of its name.
:
}
cat_markdown_test() {
cat_GENERIC_test markdown.md
}
cat_markdown_hint() {
cat_GENERIC_hint $1 markdown.md
}
cat_markdown_epilogue() {
_tutr_pressenter
}
clear_prologue() {
cat <<-:
By now you've filled up your screen with lots of text.
It's nice to get back to a fresh, blank slate.
You can clear the screen with the cleverly-named $(cmd clear) command.
Its syntax is very simple:
$(cmd clear)
Try it now.
:
}
clear_test() {
_tutr_generic_test -c clear
}
clear_hint() {
_tutr_generic_hint $1 clear
}
clear_epilogue() {
_tutr_pressenter
}
ls_a_prologue() {
cat <<-:
I wasn't being completely honest with you when I said that there were
three files. There is a stowaway among us.
$(cmd ls) can take an option $(cmd -a) that makes it show $(bld all) files, even hidden ones.
Run $(cmd ls) with the $(cmd -a) option now.
:
}
NEED_SPACES=99
NOT_WINDOWS=98
ls_a_test() {
[[ ${_CMD[0]} =~ ^ls- ]] && return $NEED_SPACES
[[ ${_CMD[0]} = dir ]] && return $NOT_WINDOWS
if [[ $_PLAT = Apple ]]; then
# `ls --all` doesn't work on MacOS
_tutr_generic_test -c ls -a -a -d "$_BASE"
else
_tutr_generic_test -c ls -a '^-a$|^--all$' -d "$_BASE"
fi
}
ls_a_hint() {
case $1 in
$NEED_SPACES)
cat <<-:
Try adding a space between $(cmd ls) and $(cmd -a).
:
;;
$NOT_WINDOWS)
cat <<-:
This isn't Windows. Use $(cmd ls) here.
:
;;
*)
_tutr_generic_hint $1 ls "$_BASE"
;;
esac
cat <<-:
Give the $(cmd ls) command the $(cmd -a) option.
:
}
ls_a_epilogue() {
_tutr_pressenter
}
cat_hidden_prologue() {
cat <<-:
Do you see the three files with names beginning with '$(bld .)'?
They may look funny, but those are valid file names in Unix.
Use $(cmd cat) to see what's in the file named $(path .hidden).
:
}
cat_hidden_test() {
cat_GENERIC_test .hidden
}
cat_hidden_hint() {
cat_GENERIC_hint $1 .hidden
}
cat_hidden_epilogue() {
_tutr_pressenter
}
reset_prologue() {
cat <<-:
So far you have learned a few ways to put text on the screen,
and you can clear it off again:
* $(cmd echo) prints its arguments
* $(cmd ls) prints a listing of files
* $(cmd cat) prints the contents of files
* $(cmd clear) erases everything on the screen
For the rest of this lesson you will leave the happy path and learn
how to cope $(_err when things go wrong).
:
_tutr_pressenter
cat <<-:
Although $(cmd cat) is intended for text files, there is nothing keeping you
from $(cmd cat)-ing non-text files like $(cyn MP3s), $(cyn PDFs), $(cyn JPEGs) or $(cyn ZIPs) to the
screen. You just might learn something from what you see.
However, there is a possibility that this will make your $(_term) go
$(mgn haywire). The effect is not permanent, and nothing is ruined.
But it can happen when you're working with data, so you need to be
prepared for it. In a moment I will make you do it on purpose.
First, I need to show you how to fix a $(mgn corrupted) $(_term) with the
$(cmd reset) command.
:
_tutr_pressenter
cat <<-:
Don't worry, this won't reboot your computer! $(cmd reset) just tells the
$(_term) to re-initialize itself so you can read it again. You'll see
what I mean in a moment.
Let's do a dry-run of $(cmd reset).
:
}
reset_test() {
_tutr_generic_test -c reset
}
reset_hint() {
_tutr_generic_hint $1 reset
}
reset_epilogue() {
cat <<-:
$(cmd reset) seems like a slower version of $(cmd clear). What good is it?
:
_tutr_pressenter
}
cat_corrupt_pre() {
_make_corrupt_terminal
}
cat_corrupt_prologue() {
cat <<-:
I just created a new file called $(path corrupt_terminal). When you display it
with $(cmd cat), raw data is sent to the $(_term) where it is misinterpreted,
resulting in an unreadable, garbled display.
You can still run commands when the $(_term) is in this state. However,
results will look like gibberish. This is because the $(_shell Shell) and the
$(_term Terminal) are two separate programs.
:
_tutr_pressenter
if [[ $_SH = Zsh ]]; then
local shel=$(cyn " Zsh")
else
local shel=$(cyn Bash)
fi
cat <<-:
${_W}+--------------+