-
Notifications
You must be signed in to change notification settings - Fork 0
/
example2.ass
848 lines (845 loc) · 71.6 KB
/
example2.ass
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
[Script Info]
; Script generated by Aegisub 3.2.2
; http://www.aegisub.org/
Title: Default Aegisub file
ScriptType: v4.00+
WrapStyle: 0
ScaledBorderAndShadow: yes
YCbCr Matrix: None
[Aegisub Project Garbage]
Active Line: 6
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1
Style: ch1_test,黑体,28,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,3,0,2,2,10,10,10,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:01.35,0:00:02.61,Default,,0,0,0,,好的,欢迎回来[*]
Dialogue: 0,0:00:03.41,0:00:07.58,Default,,0,0,0,,今天我们要分别谈谈与 Shell 有关的两个话题
Dialogue: 0,0:00:07.78,0:00:11.48,Default,,0,0,0,,首先我们要讲 Shell 脚本,这主要和 bash 有关
Dialogue: 0,0:00:11.48,0:00:16.08,Default,,0,0,0,,这将会是你们大多数人一开始在 macOS
Dialogue: 0,0:00:16.08,0:00:17.85,Default,,0,0,0,,或者大多数 Linux 里接触的 Shell
Dialogue: 0,0:00:17.85,0:00:18.85,Default,,0,0,0,,bash 是它们默认的 Shell
Dialogue: 0,0:00:19.21,0:00:20.71,Default,,0,0,0,,并且其他 Shell ,像是 zsh,,,,,
Dialogue: 0,0:00:20.71,0:00:22.78,Default,,0,0,0,,对其有良好的向后兼容,这非常棒 [*]
Dialogue: 0,0:00:22.78,0:00:26.55,Default,,0,0,0,,然后我们要谈谈特别方便的其他 Shell 工具
Dialogue: 0,0:00:26.55,0:00:29.45,Default,,0,0,0,,你们可以用它避免重复执行任务
Dialogue: 0,0:00:29.45,0:00:31.58,Default,,0,0,0,,像是寻找一段代码
Dialogue: 0,0:00:31.58,0:00:34.25,Default,,0,0,0,,或者一些犄角旮旯的文件
Dialogue: 0,0:00:34.25,0:00:36.71,Default,,0,0,0,,bash 里也有许多很棒的内置命令
Dialogue: 0,0:00:36.71,0:00:40.08,Default,,0,0,0,,它们可以帮你做这些事情
Dialogue: 0,0:00:41.88,0:00:44.61,Default,,0,0,0,,昨天我们已经介绍了 Shell
Dialogue: 0,0:00:44.61,0:00:46.65,Default,,0,0,0,,和它的一些特性
Dialogue: 0,0:00:46.65,0:00:49.28,Default,,0,0,0,,就比如说你怎样执行一个命令
Dialogue: 0,0:00:49.28,0:00:50.58,Default,,0,0,0,,或者重定向它们(的输入输出)
Dialogue: 0,0:00:50.58,0:00:52.31,Default,,0,0,0,,今天我们将多讲一些 Shell 脚本中的
Dialogue: 0,0:00:52.31,0:00:57.28,Default,,0,0,0,,操纵变量的语法,控制流以及函数
Dialogue: 0,0:00:57.91,0:01:01.35,Default,,0,0,0,,例如,一旦你接触 Shell
Dialogue: 0,0:01:01.95,0:01:03.88,Default,,0,0,0,,说你想要定义一个变量
Dialogue: 0,0:01:03.88,0:01:09.21,Default,,0,0,0,,那是你学习编程语言第一个接触的事情[*]
Dialogue: 0,0:01:09.35,0:01:12.95,Default,,0,0,0,,你可以执行像是 `foo=bar`
Dialogue: 0,0:01:13.61,0:01:18.05,Default,,0,0,0,,并且我们可以通过 `$foo` 操作 `foo` 的值
Dialogue: 0,0:01:18.81,0:01:21.01,Default,,0,0,0,,它是 `bar`,完美~
Dialogue: 0,0:01:21.81,0:01:24.45,Default,,0,0,0,,你需要多加注意的一点是
Dialogue: 0,0:01:24.45,0:01:26.71,Default,,0,0,0,,当你面对着 bash 的时候[*]
Dialogue: 0,0:01:26.71,0:01:28.25,Default,,0,0,0,,空格至关重要[*]
Dialogue: 0,0:01:28.25,0:01:33.65,Default,,0,0,0,,主要是因为空格是用于分隔参数的保留字符
Dialogue: 0,0:01:33.65,0:01:37.55,Default,,0,0,0,,例如,一些像是 `foo = bar` 的操作不管用
Dialogue: 0,0:01:37.95,0:01:42.18,Default,,0,0,0,,Shell 会告诉你它为什么无法生效
Dialogue: 0,0:01:42.18,0:01:43.95,Default,,0,0,0,,这是它说因为 `foo` 命令无法生效
Dialogue: 0,0:01:44.21,0:01:46.28,Default,,0,0,0,,比如这里提示 `foo` 不存在
Dialogue: 0,0:01:46.28,0:01:49.48,Default,,0,0,0,,实际发生的是,我们没有将 `bar` 赋给 `foo`
Dialogue: 0,0:01:50.28,0:01:56.51,Default,,0,0,0,,而是用 `=` 和 `bar` 作为参数调用了 `foo` 程序
Dialogue: 0,0:01:57.88,0:02:01.65,Default,,0,0,0,,通常,你需要特别关注这类问题
Dialogue: 0,0:02:01.88,0:02:03.95,Default,,0,0,0,,比如说一些带有空格的文件名
Dialogue: 0,0:02:03.95,0:02:10.65,Default,,0,0,0,,你需要小心地把他们用引号引起来
Dialogue: 0,0:02:10.65,0:02:14.55,Default,,0,0,0,,让我们更深入些,探讨一下怎样在 bash 中处理字符串
Dialogue: 0,0:02:14.55,0:02:16.51,Default,,0,0,0,,我们有两种定义字符串的方法:
Dialogue: 0,0:02:16.51,0:02:20.71,Default,,0,0,0,,可以用双引号定义字符串
Dialogue: 0,0:02:20.71,0:02:24.85,Default,,0,0,0,,或者可以用单……
Dialogue: 0,0:02:24.85,0:02:25.75,Default,,0,0,0,,呃,对不起
Dialogue: 0,0:02:26.71,0:02:28.01,Default,,0,0,0,,使用单引号(定义)
Dialogue: 0,0:02:30.21,0:02:33.05,Default,,0,0,0,,虽然对于纯文本字符串,这两种方式是等价的
Dialogue: 0,0:02:33.05,0:02:35.65,Default,,0,0,0,,但是对于其余的字符串,则不相同
Dialogue: 0,0:02:35.65,0:02:43.31,Default,,0,0,0,,例如,我们执行 `echo "Value is $foo"`
Dialogue: 0,0:02:43.98,0:02:47.81,Default,,0,0,0,,其中 `$foo` 将被展开为字符串
Dialogue: 0,0:02:47.81,0:02:51.05,Default,,0,0,0,,并且替换掉 Shell 中 `foo` 变量的值
Dialogue: 0,0:02:51.31,0:02:56.58,Default,,0,0,0,,如果我们用单引号来重复实验
Dialogue: 0,0:02:56.58,0:02:58.95,Default,,0,0,0,,我们仅仅会得到原样的 `$foo`
Dialogue: 0,0:02:59.35,0:03:01.88,Default,,0,0,0,,单引号中的变量将不会被替换
Dialogue: 0,0:03:01.98,0:03:04.48,Default,,0,0,0,,脚本真的十分易于编写
Dialogue: 0,0:03:04.75,0:03:08.21,Default,,0,0,0,,这个就好比…它有点像你可能更熟悉的 Python
Dialogue: 0,0:03:08.58,0:03:10.75,Default,,0,0,0,,你可能没意识到这点
Dialogue: 0,0:03:11.25,0:03:14.41,Default,,0,0,0,,这就是给变量赋值的方式
Dialogue: 0,0:03:14.41,0:03:18.18,Default,,0,0,0,,我们稍后还会看到 bash 也有控制流技术
Dialogue: 0,0:03:18.18,0:03:20.28,Default,,0,0,0,,像是 for 循环、while 循环
Dialogue: 0,0:03:20.28,0:03:24.38,Default,,0,0,0,,另一个重点是,我们可以定义函数
Dialogue: 0,0:03:24.38,0:03:28.58,Default,,0,0,0,,我们可以访问我在此处定义的函数
Dialogue: 0,0:03:28.58,0:03:32.65,Default,,0,0,0,,这里我们已经定义了 `mcd` 函数
Dialogue: 0,0:03:32.65,0:03:36.11,Default,,0,0,0,,到目前为止,我们已经了解
Dialogue: 0,0:03:36.11,0:03:38.91,Default,,0,0,0,,如何利用管道连接并执行几个命令
Dialogue: 0,0:03:38.91,0:03:40.91,Default,,0,0,0,,昨天简要地说过
Dialogue: 0,0:03:40.91,0:03:45.15,Default,,0,0,0,,但是很多时候你想先做一件事,然后另一件事
Dialogue: 0,0:03:45.15,0:03:51.11,Default,,0,0,0,,有点像我们这里的顺序执行
Dialogue: 0,0:03:51.11,0:03:53.85,Default,,0,0,0,,看这里,例如,我们可以调用 `mcd` 函数
Dialogue: 0,0:03:57.18,0:04:00.25,Default,,0,0,0,,首先我们调用 `mkdir` 命令
Dialogue: 0,0:04:00.25,0:04:02.51,Default,,0,0,0,,它会创建一个目录
Dialogue: 0,0:04:03.28,0:04:06.15,Default,,0,0,0,,在这里,`$1` 就像是一个特殊变量
Dialogue: 0,0:04:06.15,0:04:07.58,Default,,0,0,0,,这就是 bash 运作的方式
Dialogue: 0,0:04:07.58,0:04:12.31,Default,,0,0,0,,类似于其他脚本语言的 `argv`
Dialogue: 0,0:04:12.31,0:04:16.85,Default,,0,0,0,,数组 `argv` 的第一项将包含参数[*]
Dialogue: 0,0:04:16.85,0:04:18.05,Default,,0,0,0,,在 bash 中同样的东西是 `$1`
Dialogue: 0,0:04:18.05,0:04:22.38,Default,,0,0,0,,一般来说,bash 中许多 `$` 开头的东西
Dialogue: 0,0:04:22.38,0:04:23.11,Default,,0,0,0,,它们都是被保留的[*]
Dialogue: 0,0:04:23.11,0:04:25.45,Default,,0,0,0,,我们之后会看到更多的例子
Dialogue: 0,0:04:26.15,0:04:28.38,Default,,0,0,0,,一旦我们创建了文件夹,
Dialogue: 0,0:04:28.38,0:04:30.51,Default,,0,0,0,,我们就 `cd` 进去
Dialogue: 0,0:04:31.38,0:04:34.55,Default,,0,0,0,,这其实是个挺常见的流程
Dialogue: 0,0:04:34.98,0:04:38.35,Default,,0,0,0,,实际上,我们直接将其键入到 Shell
Dialogue: 0,0:04:38.35,0:04:40.28,Default,,0,0,0,,它就会起作用,定义这个函数
Dialogue: 0,0:04:40.61,0:04:45.55,Default,,0,0,0,,但是有时候,把代码写到文件里更好
Dialogue: 0,0:04:45.55,0:04:49.88,Default,,0,0,0,,然后我们就可以 `source` 这个文件
Dialogue: 0,0:04:49.88,0:04:53.61,Default,,0,0,0,,这就会在 Shell 中加载脚本并执行
Dialogue: 0,0:04:54.21,0:04:56.81,Default,,0,0,0,,虽然现在看起来无事发生
Dialogue: 0,0:04:56.81,0:05:01.35,Default,,0,0,0,,但是现在 Shell 中已经定义了 `mcd` 函数
Dialogue: 0,0:05:01.88,0:05:05.65,Default,,0,0,0,,因此我们现在能,比如说执行 `mcd test`
Dialogue: 0,0:05:05.65,0:05:09.65,Default,,0,0,0,,就从 `tool` 目录移到了 `test` 目录
Dialogue: 0,0:05:09.65,0:05:13.41,Default,,0,0,0,,我们创建了文件夹并且进入其中
Dialogue: 0,0:05:16.01,0:05:18.85,Default,,0,0,0,,还有什么。结果是...
Dialogue: 0,0:05:18.85,0:05:22.25,Default,,0,0,0,,我们可以通过 `$1` 访问第一个参数
Dialogue: 0,0:05:22.25,0:05:26.31,Default,,0,0,0,,这里有许多被保留的命令[*]
Dialogue: 0,0:05:26.31,0:05:30.08,Default,,0,0,0,,例如 `$0` 将会是脚本的名字
Dialogue: 0,0:05:30.08,0:05:32.98,Default,,0,0,0,,`$2` 到 `$9` 是 bash 脚本的
Dialogue: 0,0:05:32.98,0:05:37.35,Default,,0,0,0,,第二个到第九个参数
Dialogue: 0,0:05:37.35,0:05:42.05,Default,,0,0,0,,有一些保留字可以直接在 Shell 中使用
Dialogue: 0,0:05:42.05,0:05:50.35,Default,,0,0,0,,例如 `$?` 能获取上条命令的错误代码(返回值)
Dialogue: 0,0:05:52.45,0:05:53.75,Default,,0,0,0,,我会简要解释这些
Dialogue: 0,0:05:53.75,0:05:59.31,Default,,0,0,0,,再比如,`$_` 会获取上条命令的最后一个参数
Dialogue: 0,0:05:59.31,0:06:03.45,Default,,0,0,0,,因此,我们搞定这个的另一种方式是
Dialogue: 0,0:06:03.45,0:06:07.45,Default,,0,0,0,,我们可以执行 `mkdir test`
Dialogue: 0,0:06:07.45,0:06:10.08,Default,,0,0,0,,与其重写一遍 `test`
Dialogue: 0,0:06:10.08,0:06:13.35,Default,,0,0,0,,不如我们用 `$_` 访问上条命令的一部分
Dialogue: 0,0:06:13.35,0:06:18.45,Default,,0,0,0,,也就是最后一个参数
Dialogue: 0,0:06:18.45,0:06:20.75,Default,,0,0,0,,它将被替换成 `test`
Dialogue: 0,0:06:20.75,0:06:22.98,Default,,0,0,0,,现在我们进去了 `test` 目录
Dialogue: 0,0:06:25.58,0:06:27.61,Default,,0,0,0,,像这样的例子很多,你应当熟悉他们
Dialogue: 0,0:06:27.61,0:06:32.35,Default,,0,0,0,,另一个我经常用的叫做 `bang bang`(`!!`)
Dialogue: 0,0:06:32.35,0:06:36.65,Default,,0,0,0,,每当,比如说,你试着创建某些东西
Dialogue: 0,0:06:36.65,0:06:37.85,Default,,0,0,0,,但你没有足够权限的时候
Dialogue: 0,0:06:37.85,0:06:39.11,Default,,0,0,0,,正是这个东西的用武之处
Dialogue: 0,0:06:39.11,0:06:41.05,Default,,0,0,0,,然后,你可以执行 `sudo !!`
Dialogue: 0,0:06:41.48,0:06:44.75,Default,,0,0,0,,`!!` 会被你刚刚尝试的命令取代
Dialogue: 0,0:06:44.75,0:06:46.78,Default,,0,0,0,,现在来试一下
Dialogue: 0,0:06:46.78,0:06:48.65,Default,,0,0,0,,现在它就提示我输入密码
Dialogue: 0,0:06:48.65,0:06:50.51,Default,,0,0,0,,因为我有了 sudo 权限
Dialogue: 0,0:06:57.45,0:06:58.65,Default,,0,0,0,,之前我提到了,呃,命令错误什么的
Dialogue: 0,0:06:58.65,0:06:59.71,Default,,0,0,0,,昨天我们看过,总体来说……
Dialogue: 0,0:06:59.71,0:07:01.08,Default,,0,0,0,,一个进程有许多方式
Dialogue: 0,0:07:01.08,0:07:04.71,Default,,0,0,0,,和其他进程或命令交互
Dialogue: 0,0:07:05.18,0:07:07.51,Default,,0,0,0,,我们提到了标准输入(流)
Dialogue: 0,0:07:07.51,0:07:08.78,Default,,0,0,0,,它就是好比……
Dialogue: 0,0:07:08.78,0:07:10.31,Default,,0,0,0,,(程序)从标准输入获取各种东西
Dialogue: 0,0:07:10.31,0:07:11.51,Default,,0,0,0,,然后把东西输到标准输出里
Dialogue: 0,0:07:11.51,0:07:13.88,Default,,0,0,0,,还有些东西更有意思
Dialogue: 0,0:07:14.15,0:07:18.05,Default,,0,0,0,,也有一个标准错误(流)
Dialogue: 0,0:07:18.55,0:07:21.65,Default,,0,0,0,,如果你程序出错了
Dialogue: 0,0:07:21.65,0:07:22.81,Default,,0,0,0,,你想输出错误却不污染标准输出
Dialogue: 0,0:07:22.91,0:07:24.08,Default,,0,0,0,,就可以写进这个流
Dialogue: 0,0:07:24.08,0:07:26.15,Default,,0,0,0,,也有错误代码(error code)这种东西
Dialogue: 0,0:07:26.41,0:07:29.78,Default,,0,0,0,,而且它普遍存在于很多编程语言
Dialogue: 0,0:07:29.78,0:07:33.55,Default,,0,0,0,,是一种告诉你整个运行过程
Dialogue: 0,0:07:33.65,0:07:34.28,Default,,0,0,0,,结果如何的方式
Dialogue: 0,0:07:34.98,0:07:37.15,Default,,0,0,0,,所以,比如我们试试
Dialogue: 0,0:07:37.55,0:07:39.75,Default,,0,0,0,,`echo "Hello"`
Dialogue: 0,0:07:39.91,0:07:43.45,Default,,0,0,0,,然后查一下错误代码的值,它是 `0`
Dialogue: 0,0:07:43.45,0:07:45.61,Default,,0,0,0,,`0` 是因为一切正常,没有出问题
Dialogue: 0,0:07:45.61,0:07:47.95,Default,,0,0,0,,这种 `0` 退出码和它在[*]
Dialogue: 0,0:07:48.48,0:07:51.78,Default,,0,0,0,,比如 C 这种语言里,代表的意思一样
Dialogue: 0,0:07:52.18,0:07:54.85,Default,,0,0,0,,`0` 就代表所有事情正常,没出错误
Dialogue: 0,0:07:55.38,0:07:57.25,Default,,0,0,0,,然而,有时候事情会出错
Dialogue: 0,0:07:57.71,0:08:02.85,Default,,0,0,0,,比如有时候,我们尝试在 `mcd` 脚本里
Dialogue: 0,0:08:02.85,0:08:04.85,Default,,0,0,0,,`grep foobar` 的话
Dialogue: 0,0:08:05.08,0:08:07.85,Default,,0,0,0,,现在查一下值,就是 `1`
Dialogue: 0,0:08:07.85,0:08:11.08,Default,,0,0,0,,这是因为我们试着在 `mcd` 脚本里
Dialogue: 0,0:08:11.08,0:08:13.78,Default,,0,0,0,,搜索 `foobar` 字符串,而它不存在
Dialogue: 0,0:08:14.28,0:08:17.58,Default,,0,0,0,,所以 `grep` 什么都没输出
Dialogue: 0,0:08:17.58,0:08:19.91,Default,,0,0,0,,但是通过反馈一个 `1` 的错误代码
Dialogue: 0,0:08:19.95,0:08:21.95,Default,,0,0,0,,它让我们知道这件事没成功
Dialogue: 0,0:08:22.35,0:08:24.58,Default,,0,0,0,,有一些有意思的命令,比如
Dialogue: 0,0:08:24.91,0:08:30.48,Default,,0,0,0,,`true` 的错误代码始终是 `0`
Dialogue: 0,0:08:30.48,0:08:34.85,Default,,0,0,0,,`false` 的错误代码则是 `1`
Dialogue: 0,0:08:35.51,0:08:39.28,Default,,0,0,0,,还有比如这些逻辑运算符
Dialogue: 0,0:08:39.28,0:08:43.25,Default,,0,0,0,,你可以用来做条件判断
Dialogue: 0,0:08:43.25,0:08:45.75,Default,,0,0,0,,比如……其实你也有 `if-else`
Dialogue: 0,0:08:45.75,0:08:46.45,Default,,0,0,0,,之后我们会说
Dialogue: 0,0:08:46.65,0:08:48.48,Default,,0,0,0,,但是现在你可以做一些
Dialogue: 0,0:08:48.98,0:08:52.25,Default,,0,0,0,,比如 `false`,然后 `echo "Oops fail"`
Dialogue: 0,0:08:52.25,0:08:56.28,Default,,0,0,0,,这里有两个被或运算符链接的命令
Dialogue: 0,0:08:56.28,0:09:00.61,Default,,0,0,0,,这里 bash 要做的是,执行第一个命令
Dialogue: 0,0:09:00.61,0:09:05.95,Default,,0,0,0,,如果第一个命令失败,再去执行第二个[*]
Dialogue: 0,0:09:05.95,0:09:08.11,Default,,0,0,0,,这里我们有这个结果
Dialogue: 0,0:09:08.11,0:09:10.55,Default,,0,0,0,,因为它尝试做一个逻辑或
Dialogue: 0,0:09:10.55,0:09:12.95,Default,,0,0,0,,如果第一个(命令)没有 `0` 错误码
Dialogue: 0,0:09:12.95,0:09:14.58,Default,,0,0,0,,它就会去执行第二个(命令)
Dialogue: 0,0:09:14.58,0:09:18.25,Default,,0,0,0,,相似地,如果我们把 `false`
Dialogue: 0,0:09:18.25,0:09:19.55,Default,,0,0,0,,替换成比如 `true`
Dialogue: 0,0:09:19.55,0:09:22.01,Default,,0,0,0,,因为我们有一个 `0` 错误代码
Dialogue: 0,0:09:22.01,0:09:24.18,Default,,0,0,0,,所以第二个(命令)会被短路
Dialogue: 0,0:09:24.18,0:09:26.75,Default,,0,0,0,,所以就不会打印
Dialogue: 0,0:09:32.78,0:09:35.65,Default,,0,0,0,,相似地,我们有与运算符
Dialogue: 0,0:09:36.65,0:09:38.81,Default,,0,0,0,,它仅当第一个命令执行无错误时
Dialogue: 0,0:09:38.88,0:09:41.35,Default,,0,0,0,,才会执行第二个部分
Dialogue: 0,0:09:43.58,0:09:45.05,Default,,0,0,0,,这里也是同样的事情:
Dialogue: 0,0:09:45.11,0:09:48.08,Default,,0,0,0,,如果第一个失败,那么第二个命令
Dialogue: 0,0:09:48.08,0:09:49.48,Default,,0,0,0,,就不会被执行
Dialogue: 0,0:09:51.71,0:09:57.01,Default,,0,0,0,,虽然不是很相关,但是另一个事情是
Dialogue: 0,0:10:01.75,0:10:04.65,Default,,0,0,0,,无论你执行什么,你都可以通过
Dialogue: 0,0:10:04.65,0:10:07.08,Default,,0,0,0,,在同一行内使用分号来连接命令
Dialogue: 0,0:10:07.08,0:10:09.08,Default,,0,0,0,,它就会始终被打印出来
Dialogue: 0,0:10:10.31,0:10:13.68,Default,,0,0,0,,在这之后,我们还没学到的是
Dialogue: 0,0:10:13.68,0:10:19.68,Default,,0,0,0,,怎样把命令的输出存到变量里
Dialogue: 0,0:10:19.68,0:10:24.21,Default,,0,0,0,,我们可以这样做
Dialogue: 0,0:10:24.55,0:10:29.88,Default,,0,0,0,,这里我们获取 `pwd` 命令的输出
Dialogue: 0,0:10:29.88,0:10:32.58,Default,,0,0,0,,它会打印出当前工作目录
Dialogue: 0,0:10:32.58,0:10:33.61,Default,,0,0,0,,也就是我们在哪里
Dialogue: 0,0:10:33.95,0:10:36.95,Default,,0,0,0,,然后把这个存进 `foo` 变量
Dialogue: 0,0:10:37.65,0:10:41.11,Default,,0,0,0,,然后现在我们询问 `foo` 的值
Dialogue: 0,0:10:41.11,0:10:42.41,Default,,0,0,0,,我们就能看到这个字符串
Dialogue: 0,0:10:42.41,0:10:45.18,Default,,0,0,0,,更广泛的说,我们可以做一个叫
Dialogue: 0,0:10:45.85,0:10:48.48,Default,,0,0,0,,命令替换的事情
Dialogue: 0,0:10:50.01,0:10:51.35,Default,,0,0,0,,通过把它放进任意字符串中
Dialogue: 0,0:10:51.35,0:10:54.55,Default,,0,0,0,,而且因为我们用的不是单引号
Dialogue: 0,0:10:54.55,0:10:55.45,Default,,0,0,0,,而是双引号
Dialogue: 0,0:10:55.45,0:10:57.15,Default,,0,0,0,,所以这串东西会被展开
Dialogue: 0,0:10:57.15,0:11:02.21,Default,,0,0,0,,告诉我们,现在位于这个文件夹
Dialogue: 0,0:11:03.81,0:11:05.58,Default,,0,0,0,,另一个有趣的事情是
Dialogue: 0,0:11:06.21,0:11:09.55,Default,,0,0,0,,这个会展开成一个字符串
Dialogue: 0,0:11:09.55,0:11:09.98,Default,,0,0,0,,而不是……
Dialogue: 0,0:11:09.98,0:11:13.28,Default,,0,0,0,,呃,它只是展开成一个字符串
Dialogue: 0,0:11:13.28,0:11:16.48,Default,,0,0,0,,另一个好用但知名度更低的工具
Dialogue: 0,0:11:16.48,0:11:17.88,Default,,0,0,0,,叫做过程替换
Dialogue: 0,0:11:18.18,0:11:20.78,Default,,0,0,0,,和之前那个是类似的
Dialogue: 0,0:11:24.28,0:11:25.71,Default,,0,0,0,,它会做什么呢……它会
Dialogue: 0,0:11:26.91,0:11:31.11,Default,,0,0,0,,比如这里的 `<(` ,接一个命令,再接 `)`
Dialogue: 0,0:11:31.11,0:11:33.98,Default,,0,0,0,,它的作用是,内部的命令会被执行
Dialogue: 0,0:11:33.98,0:11:35.98,Default,,0,0,0,,其输出将被存储到,大概像一个
Dialogue: 0,0:11:35.98,0:11:38.35,Default,,0,0,0,,临时文件内,然后把文件 handle(标识符)[*]
Dialogue: 0,0:11:38.35,0:11:39.48,Default,,0,0,0,,交给(最左面的)命令
Dialogue: 0,0:11:39.48,0:11:42.58,Default,,0,0,0,,所以这里我们在……`ls` 这个目录
Dialogue: 0,0:11:42.58,0:11:45.78,Default,,0,0,0,,把输出放到临时文件内
Dialogue: 0,0:11:45.78,0:11:47.98,Default,,0,0,0,,再对父目录如法炮制
Dialogue: 0,0:11:47.98,0:11:50.38,Default,,0,0,0,,然后把两个文件连接
Dialogue: 0,0:11:50.38,0:11:53.11,Default,,0,0,0,,而这种写法就非常得劲
Dialogue: 0,0:11:53.11,0:11:54.38,Default,,0,0,0,,因为有些命令会从
Dialogue: 0,0:11:54.38,0:11:57.78,Default,,0,0,0,,某些文件的内容,而不是标准输入
Dialogue: 0,0:11:57.78,0:12:03.35,Default,,0,0,0,,获得输入参数
Dialogue: 0,0:12:04.88,0:12:07.91,Default,,0,0,0,,所以我们把这两个命令连起来了
Dialogue: 0,0:12:13.01,0:12:15.75,Default,,0,0,0,,感觉讲到现在,讲了真不少东西
Dialogue: 0,0:12:15.75,0:12:18.48,Default,,0,0,0,,来看一个里面包含这些内容的
Dialogue: 0,0:12:18.48,0:12:24.21,Default,,0,0,0,,简单的示例脚本
Dialogue: 0,0:12:24.21,0:12:26.98,Default,,0,0,0,,比如说这里我们有个字符串
Dialogue: 0,0:12:26.98,0:12:29.45,Default,,0,0,0,,然后有个 `$(date)`
Dialogue: 0,0:12:29.45,0:12:30.98,Default,,0,0,0,,这个 `date` 是个程序
Dialogue: 0,0:12:30.98,0:12:33.05,Default,,0,0,0,,重复一下,类 UNIX 系统有很多程序
Dialogue: 0,0:12:33.05,0:12:36.08,Default,,0,0,0,,你会慢慢都熟悉它们的
Dialogue: 0,0:12:36.08,0:12:39.75,Default,,0,0,0,,`date` 就打印出当前的日期
Dialogue: 0,0:12:39.75,0:12:41.88,Default,,0,0,0,,你还可以指定各种打印格式
Dialogue: 0,0:12:42.48,0:12:47.28,Default,,0,0,0,,然后这里有这个 `$0`
Dialogue: 0,0:12:47.28,0:12:50.28,Default,,0,0,0,,是我们运行的这个脚本的文件名
Dialogue: 0,0:12:50.71,0:12:57.48,Default,,0,0,0,,然后是这个 `$#`,代表给定的参数个数
Dialogue: 0,0:12:57.48,0:13:01.95,Default,,0,0,0,,然后 `$$` 是这个命令的进程 ID[*]
Dialogue: 0,0:13:02.78,0:13:05.25,Default,,0,0,0,,强调,这里有很多 `$`+ 什么什么
Dialogue: 0,0:13:05.25,0:13:06.55,Default,,0,0,0,,它们(的含义)并不直观
Dialogue: 0,0:13:06.55,0:13:10.08,Default,,0,0,0,,因为你找不到一种巧记的方法
Dialogue: 0,0:13:10.08,0:13:12.15,Default,,0,0,0,,`$#` 这种大概就是
Dialogue: 0,0:13:12.15,0:13:13.78,Default,,0,0,0,,但是……你一直和它们打照面
Dialogue: 0,0:13:13.78,0:13:14.41,Default,,0,0,0,,逐渐就能熟络起来
Dialogue: 0,0:13:14.41,0:13:16.78,Default,,0,0,0,,这里还有个 `$@`
Dialogue: 0,0:13:16.78,0:13:19.31,Default,,0,0,0,,可以展开成所有参数
Dialogue: 0,0:13:19.31,0:13:23.21,Default,,0,0,0,,所以比起来……比如有三个参数
Dialogue: 0,0:13:23.21,0:13:25.81,Default,,0,0,0,,那我可以键入 `$1 $2 $3`
Dialogue: 0,0:13:25.81,0:13:28.25,Default,,0,0,0,,那如果我们不知道有多少参数
Dialogue: 0,0:13:28.25,0:13:29.85,Default,,0,0,0,,我们可以用这种方式把这些参数全部放在这里
Dialogue: 0,0:13:29.85,0:13:34.38,Default,,0,0,0,,然后这些参数被传给 `for` 循环
Dialogue: 0,0:13:35.11,0:13:39.28,Default,,0,0,0,,`for` 循环会创建一个 `file` 变量
Dialogue: 0,0:13:39.28,0:13:47.91,Default,,0,0,0,,依次地用这些参数赋值给 `file` 变量
Dialogue: 0,0:13:47.91,0:13:53.58,Default,,0,0,0,,下一行我们运行 `grep` 命令
Dialogue: 0,0:13:53.71,0:13:56.75,Default,,0,0,0,,它会在一堆文件里搜索一个子串[*]
Dialogue: 0,0:13:56.75,0:13:59.38,Default,,0,0,0,,这里我们在文件里搜索字符串 `foobar`
Dialogue: 0,0:13:59.98,0:14:05.91,Default,,0,0,0,,这里我们让 `file` 变量展开为它的值
Dialogue: 0,0:14:06.45,0:14:10.35,Default,,0,0,0,,昨天说过,如果我们在意程序输出的话
Dialogue: 0,0:14:10.35,0:14:13.38,Default,,0,0,0,,我们可以把它重定向到某处
Dialogue: 0,0:14:13.38,0:14:15.71,Default,,0,0,0,,到一个文件里保存下来,或者连接组合
Dialogue: 0,0:14:16.41,0:14:19.18,Default,,0,0,0,,嘿,但有时候情况恰恰相反
Dialogue: 0,0:14:19.18,0:14:21.28,Default,,0,0,0,,有时候,比如说,我们想知道
Dialogue: 0,0:14:21.28,0:14:23.95,Default,,0,0,0,,这个脚本的错误代码是什么
Dialogue: 0,0:14:23.95,0:14:28.05,Default,,0,0,0,,我想知道 `grep` 能不能成功查找
Dialogue: 0,0:14:28.61,0:14:33.21,Default,,0,0,0,,所以,我们甚至能直接扔掉整个输出
Dialogue: 0,0:14:33.21,0:14:37.88,Default,,0,0,0,,包括标准输出和标准错误(流)
Dialogue: 0,0:14:38.48,0:14:39.51,Default,,0,0,0,,这里我们做的是
Dialogue: 0,0:14:39.51,0:14:43.05,Default,,0,0,0,,把两个输出重定向到 `/dev/null`
Dialogue: 0,0:14:43.05,0:14:47.11,Default,,0,0,0,,它是 UNIX 系统的一种特殊设备
Dialogue: 0,0:14:47.11,0:14:50.51,Default,,0,0,0,,输出到它的内容会被丢弃
Dialogue: 0,0:14:50.58,0:14:53.38,Default,,0,0,0,,就是你可以随意乱写乱画
Dialogue: 0,0:14:53.38,0:14:53.58,Default,,0,0,0,,然后所有内容都会被丢掉\N就是你可以随意乱写乱画
Dialogue: 0,0:14:53.58,0:14:54.48,Default,,0,0,0,,然后所有内容都会被丢掉
Dialogue: 0,0:14:54.71,0:14:58.18,Default,,0,0,0,,还有这个 `>` 符号
Dialogue: 0,0:14:58.18,0:15:00.18,Default,,0,0,0,,昨天说过,用来重定向输出的
Dialogue: 0,0:15:00.45,0:15:02.88,Default,,0,0,0,,这里有个 `2>`
Dialogue: 0,0:15:03.18,0:15:05.58,Default,,0,0,0,,有些人也许猜到了
Dialogue: 0,0:15:05.58,0:15:07.55,Default,,0,0,0,,它是重定向标准错误流的
Dialogue: 0,0:15:07.55,0:15:10.25,Default,,0,0,0,,因为这两个流是分立的
Dialogue: 0,0:15:10.25,0:15:14.15,Default,,0,0,0,,所以你得告诉 bash 去操作哪个
Dialogue: 0,0:15:15.28,0:15:16.58,Default,,0,0,0,,所以这里我们执行命令
Dialogue: 0,0:15:16.58,0:15:18.38,Default,,0,0,0,,去检查文件有没有 `foobar`
Dialogue: 0,0:15:18.38,0:15:22.78,Default,,0,0,0,,如果有的话,返回一个 `0` 错误码
Dialogue: 0,0:15:22.78,0:15:25.65,Default,,0,0,0,,如果没有,就是一个非 `0` 码
Dialogue: 0,0:15:26.05,0:15:27.98,Default,,0,0,0,,我们正是要检查这个
Dialogue: 0,0:15:28.55,0:15:31.28,Default,,0,0,0,,这部分命令里
Dialogue: 0,0:15:31.28,0:15:33.75,Default,,0,0,0,,我们先告诉它:「给我错误代码」
Dialogue: 0,0:15:33.75,0:15:35.18,Default,,0,0,0,,这个是用 `$?`
Dialogue: 0,0:15:35.18,0:15:38.95,Default,,0,0,0,,然后是一个比较运算符 `-ne`
Dialogue: 0,0:15:38.95,0:15:39.81,Default,,0,0,0,,代表不等于(`N`on `E`qual)
Dialogue: 0,0:15:41.08,0:15:43.88,Default,,0,0,0,,其他编程语言里有像
Dialogue: 0,0:15:44.25,0:15:48.31,Default,,0,0,0,,`==` 和 `!=` 这种符号
Dialogue: 0,0:15:48.88,0:15:52.68,Default,,0,0,0,,bash 里有很多预设的比较运算
Dialogue: 0,0:15:52.68,0:15:56.88,Default,,0,0,0,,这主要是为了你用 Shell 的时候
Dialogue: 0,0:15:56.88,0:15:58.45,Default,,0,0,0,,有很多东西要去做测试
Dialogue: 0,0:15:58.71,0:16:00.85,Default,,0,0,0,, 比如我们现在正在对比两个数
Dialogue: 0,0:16:00.85,0:16:03.65,Default,,0,0,0,,两个整数,看它们是否相同
Dialogue: 0,0:16:03.65,0:16:08.08,Default,,0,0,0,,又比如,`-f` flag 会让我们知道
Dialogue: 0,0:16:08.08,0:16:10.01,Default,,0,0,0,,是否存在一个文件
Dialogue: 0,0:16:10.35,0:16:13.55,Default,,0,0,0,,这是你以后会频繁用上的
Dialogue: 0,0:16:16.88,0:16:18.41,Default,,0,0,0,,回到例子
Dialogue: 0,0:16:18.41,0:16:28.28,Default,,0,0,0,,如果文件中没有 `foobar` 会发生什么
Dialogue: 0,0:16:28.28,0:16:31.45,Default,,0,0,0,,像之前有非 `0` 的错误代码
Dialogue: 0,0:16:31.45,0:16:32.48,Default,,0,0,0,,我们也输出
Dialogue: 0,0:16:32.48,0:16:33.65,Default,,0,0,0,,文件中没有 `foobar` 字符串
Dialogue: 0,0:16:33.65,0:16:37.05,Default,,0,0,0,,我们将添加一个,而我们所做的是
Dialogue: 0,0:16:37.48,0:16:40.05,Default,,0,0,0,,我们输入 `# foobar`
Dialogue: 0,0:16:40.05,0:16:42.25,Default,,0,0,0,,蒙一手这 `#` 是个文件注释格式
Dialogue: 0,0:16:42.61,0:16:48.45,Default,,0,0,0,,之后我们用 `>>` 操作符把它添在文件末尾
Dialogue: 0,0:16:48.45,0:16:52.55,Default,,0,0,0,,这里尽管文件名已经传给了脚本
Dialogue: 0,0:16:52.55,0:16:53.58,Default,,0,0,0,,但我们预先并不知道文件名
Dialogue: 0,0:16:53.58,0:16:56.98,Default,,0,0,0,,所以我们需要用文件名变量在这里展开
Dialogue: 0,0:16:58.41,0:17:01.48,Default,,0,0,0,,我们可以运行这个试试
Dialogue: 0,0:17:02.05,0:17:05.28,Default,,0,0,0,,我们已经有这个脚本的正确权限
Dialogue: 0,0:17:05.75,0:17:09.78,Default,,0,0,0,,我可以举一些例子,我们在这个夹里有一些文件
Dialogue: 0,0:17:09.78,0:17:13.45,Default,,0,0,0,,`mcd` 是我们先前看到的 `mcd` 函数
Dialogue: 0,0:17:13.45,0:17:15.08,Default,,0,0,0,,还有其它脚本函数
Dialogue: 0,0:17:15.25,0:17:21.48,Default,,0,0,0,,甚至可以把它自己传给它,检查是否有 `foobar`
Dialogue: 0,0:17:22.45,0:17:25.15,Default,,0,0,0,,我们运行它,首先我们可以看到
Dialogue: 0,0:17:25.15,0:17:31.41,Default,,0,0,0,,我们成功地列出了很多的变量
Dialogue: 0,0:17:31.88,0:17:33.18,Default,,0,0,0,,我们有 `date` 命令
Dialogue: 0,0:17:33.48,0:17:36.35,Default,,0,0,0,,它成功地被替换成了当前时间
Dialogue: 0,0:17:36.58,0:17:40.05,Default,,0,0,0,,接着是这个带着三个参数的程序
Dialogue: 0,0:17:40.55,0:17:44.15,Default,,0,0,0,,它的随机的 pid 识别码
Dialogue: 0,0:17:44.45,0:17:47.18,Default,,0,0,0,,之后它告诉我们 `mcd` 没有 `foobar` 字符串
Dialogue: 0,0:17:47.18,0:17:49.21,Default,,0,0,0,,所以我们新添加了一个
Dialogue: 0,0:17:49.21,0:17:51.15,Default,,0,0,0,,并且这个 `script.py` 文件也没有
Dialogue: 0,0:17:51.15,0:17:53.55,Default,,0,0,0,,像现在让我们看看 `mcd`
Dialogue: 0,0:17:53.55,0:17:55.65,Default,,0,0,0,,它就有我们要找的注释
Dialogue: 0,0:17:59.38,0:18:05.55,Default,,0,0,0,,当你在执行脚本时另一个需要知道的是
Dialogue: 0,0:18:06.31,0:18:08.98,Default,,0,0,0,,像这里,我们有三个完全不同的参数
Dialogue: 0,0:18:09.28,0:18:10.55,Default,,0,0,0,,但通常
Dialogue: 0,0:18:10.55,0:18:16.25,Default,,0,0,0,,你会用一些更加简洁的方式输入参数
Dialogue: 0,0:18:16.61,0:18:18.98,Default,,0,0,0,,例如这里,
Dialogue: 0,0:18:19.48,0:18:24.88,Default,,0,0,0,,如果我想查找所有的 `.sh` 脚本
Dialogue: 0,0:18:25.35,0:18:30.95,Default,,0,0,0,,我们只需要键入 `ls *.sh`
Dialogue: 0,0:18:30.95,0:18:36.25,Default,,0,0,0,,这是大多数 Shell 都有的一种展开文件名的方式
Dialogue: 0,0:18:36.25,0:18:37.31,Default,,0,0,0,,叫做通配
Dialogue: 0,0:18:37.31,0:18:40.15,Default,,0,0,0,,这里,如你所想,会显示出
Dialogue: 0,0:18:40.15,0:18:44.85,Default,,0,0,0,,所有含有任意字符,且以 `.sh` 为后缀的东西
Dialogue: 0,0:18:46.85,0:18:50.55,Default,,0,0,0,,如我们所料,得到了 `example.sh` 和 `mcd.sh`
Dialogue: 0,0:18:51.05,0:18:54.08,Default,,0,0,0,,我们也有这些 `project1` 和 `project2`
Dialogue: 0,0:18:54.08,0:18:55.85,Default,,0,0,0,,并且如果这里有……
Dialogue: 0,0:18:56.48,0:19:00.18,Default,,0,0,0,,比如,我们可以建一个 `project42`
Dialogue: 0,0:19:00.78,0:19:06.38,Default,,0,0,0,,现在如果我只想找有一个特定字符的项
Dialogue: 0,0:19:06.38,0:19:07.45,Default,,0,0,0,,而不是两个字符
Dialogue: 0,0:19:07.45,0:19:08.95,Default,,0,0,0,,然后,像其它任意的字符
Dialogue: 0,0:19:08.95,0:19:14.15,Default,,0,0,0,,我们可以使用 `?` 标记,`?` 标记只会展开一个字符
Dialogue: 0,0:19:15.28,0:19:16.98,Default,,0,0,0,,我们得到了列出的
Dialogue: 0,0:19:16.98,0:19:20.21,Default,,0,0,0,,先是 `project1` 再是 `project2`
Dialogue: 0,0:19:20.98,0:19:27.41,Default,,0,0,0,,总而言之,通配符非常强大,你也可以组合它们
Dialogue: 0,0:19:32.81,0:19:35.81,Default,,0,0,0,,一个常用模式是花括号
Dialogue: 0,0:19:36.28,0:19:39.58,Default,,0,0,0,,我们在这个文件夹里有一个图片
Dialogue: 0,0:19:39.58,0:19:43.58,Default,,0,0,0,,我们想把图片文件格式由 PNG 转为 JPG
Dialogue: 0,0:19:44.31,0:19:46.25,Default,,0,0,0,,我们可能会复制它,或者……
Dialogue: 0,0:19:46.25,0:19:50.71,Default,,0,0,0,,这确实是常见情况,有两个或多个挺相似的参数
Dialogue: 0,0:19:50.71,0:19:55.15,Default,,0,0,0,,你想把它们当作参数传给命令
Dialogue: 0,0:19:55.15,0:19:58.78,Default,,0,0,0,,你可以这样做,但更简洁的做法是
Dialogue: 0,0:19:58.78,0:20:08.55,Default,,0,0,0,,你可以只键入 `image.{png,jpg}`
Dialogue: 0,0:20:10.28,0:20:12.75,Default,,0,0,0,,这里有一些彩色的反馈……
Dialogue: 0,0:20:12.75,0:20:17.45,Default,,0,0,0,,总之,它会展开成上面的那行
Dialogue: 0,0:20:17.45,0:20:21.25,Default,,0,0,0,,实际上,我可以让 zsh 为我做这些
Dialogue: 0,0:20:21.25,0:20:23.25,Default,,0,0,0,,也就是这里正进行的
Dialogue: 0,0:20:24.78,0:20:26.88,Default,,0,0,0,,这确实很强大,所以比如
Dialogue: 0,0:20:26.88,0:20:29.78,Default,,0,0,0,,你可以做一些像……我们可以……
Dialogue: 0,0:20:30.11,0:20:34.08,Default,,0,0,0,,`touch` 一串 `foo`,所有 `foo` 都会被展开
Dialogue: 0,0:20:36.35,0:20:41.55,Default,,0,0,0,,你也可以进行多层操作,建立笛卡尔系
Dialogue: 0,0:20:44.28,0:20:45.55,Default,,0,0,0,,如果我们有一些像这样的组
Dialogue: 0,0:20:47.08,0:20:50.21,Default,,0,0,0,,我们这里有一组 `{1,2}`
Dialogue: 0,0:20:50.21,0:20:52.58,Default,,0,0,0,,之后这里又有 `{1,2,3}`
Dialogue: 0,0:20:52.58,0:20:56.45,Default,,0,0,0,,这会用使两组展开式形成笛卡尔积
Dialogue: 0,0:20:56.45,0:20:59.28,Default,,0,0,0,,而后展开积里的所有表达式
Dialogue: 0,0:21:00.85,0:21:03.05,Default,,0,0,0,,我们就可以很快地 `touch` 了
Dialogue: 0,0:21:03.68,0:21:10.58,Default,,0,0,0,,你也可以将 `*` 通配符与 `{}` 通配符结合
Dialogue: 0,0:21:11.05,0:21:13.85,Default,,0,0,0,,甚至你可以用一些范围表示
Dialogue: 0,0:21:13.95,0:21:16.78,Default,,0,0,0,,像,我们可以键入 `mkdir`
Dialogue: 0,0:21:16.78,0:21:20.01,Default,,0,0,0,,我们创建 `foo`,`bar` 目录
Dialogue: 0,0:21:20.95,0:21:25.15,Default,,0,0,0,,之后可以在这些行里搞事情
Dialogue: 0,0:21:25.45,0:21:29.28,Default,,0,0,0,,这将会展开到 `foo/a`,`foo/b` ……
Dialogue: 0,0:21:29.28,0:21:31.45,Default,,0,0,0,,像所有的组合,直到 `j`
Dialogue: 0,0:21:32.15,0:21:36.51,Default,,0,0,0,,`bar` 同理,虽然说实话我没试……
Dialogue: 0,0:21:36.51,0:21:39.78,Default,,0,0,0,,但是没错,我们得到了我们所能 touch 的所有组合
Dialogue: 0,0:21:40.45,0:21:45.78,Default,,0,0,0,,现在,如果我们在两个目录中建一些不同的东西
Dialogue: 0,0:21:46.55,0:21:53.78,Default,,0,0,0,,我们可以再次展示……
Dialogue: 0,0:21:54.45,0:21:56.38,Default,,0,0,0,,用我们之前看到的流程代替
Dialogue: 0,0:21:56.38,0:22:00.38,Default,,0,0,0,,我们想查看这两个文件夹中有什么不同文件
Dialogue: 0,0:22:00.38,0:22:03.31,Default,,0,0,0,,非常显然,我们刚刚看到了,是 `x` 和 `y`
Dialogue: 0,0:22:03.31,0:22:06.68,Default,,0,0,0,,但是我们可以用 Shell 去比对
Dialogue: 0,0:22:06.68,0:22:09.45,Default,,0,0,0,,一个 `ls` 和另一个 `ls` 输出的不同
Dialogue: 0,0:22:10.58,0:22:12.35,Default,,0,0,0,,如我们所料,我们得到了
Dialogue: 0,0:22:12.35,0:22:14.18,Default,,0,0,0,,`x` 只在第一个文件夹里
Dialogue: 0,0:22:14.18,0:22:17.85,Default,,0,0,0,,`y` 只在第二个文件夹里
Dialogue: 0,0:22:20.55,0:22:25.35,Default,,0,0,0,,还有,目前我们只看了 bash 脚本
Dialogue: 0,0:22:25.35,0:22:27.15,Default,,0,0,0,,如果你喜欢其它的脚本……
Dialogue: 0,0:22:27.15,0:22:30.15,Default,,0,0,0,,像 bash 对一些工作可能并不是最好的选择
Dialogue: 0,0:22:30.55,0:22:32.65,Default,,0,0,0,,它可能会很棘手。事实上你可以
Dialogue: 0,0:22:32.65,0:22:36.55,Default,,0,0,0,,用很多语言写和 Shell 工具交互的脚本
Dialogue: 0,0:22:37.08,0:22:40.08,Default,,0,0,0,,例如,我们在这里看一个
Dialogue: 0,0:22:40.08,0:22:43.85,Default,,0,0,0,,Python 脚本,它的开头有神秘的一行代码
Dialogue: 0,0:22:43.85,0:22:45.95,Default,,0,0,0,,我暂且不去解释
Dialogue: 0,0:22:45.95,0:22:48.38,Default,,0,0,0,,我们有 `import sys`
Dialogue: 0,0:22:48.38,0:22:56.15,Default,,0,0,0,,这很像…… Python 默认不会尝试和 Shell 交互
Dialogue: 0,0:22:56.15,0:22:57.88,Default,,0,0,0,,所以你需要导入一些库
Dialogue: 0,0:22:57.88,0:22:59.38,Default,,0,0,0,,之后我们在做一个
Dialogue: 0,0:22:59.38,0:23:00.78,Default,,0,0,0,,确实很傻的事情
Dialogue: 0,0:23:01.15,0:23:04.18,Default,,0,0,0,,就只是迭代 `sys.argv[1:]`
Dialogue: 0,0:23:05.58,0:23:09.08,Default,,0,0,0,,`sys.argv` 是一种类似于
Dialogue: 0,0:23:09.08,0:23:12.08,Default,,0,0,0,,bash 中 `$0`,`$1` 等等的东西
Dialogue: 0,0:23:12.08,0:23:17.18,Default,,0,0,0,,就是一个参数 vector,我们将它倒序输出
Dialogue: 0,0:23:19.35,0:23:22.38,Default,,0,0,0,,开始时那神奇的一行叫做 shebang[*]
Dialogue: 0,0:23:22.38,0:23:26.48,Default,,0,0,0,,Shell 通过它了解怎么运行这个程序
Dialogue: 0,0:23:26.48,0:23:30.65,Default,,0,0,0,,你随时可以键入类似
Dialogue: 0,0:23:30.65,0:23:33.45,Default,,0,0,0,,python script.py` 之后是 `a b c`
Dialogue: 0,0:23:34.05,0:23:36.65,Default,,0,0,0,,像这样它就会运行
Dialogue: 0,0:23:36.65,0:23:41.05,Default,,0,0,0,,但如果我想让它从 Shell 就能执行呢?
Dialogue: 0,0:23:41.05,0:23:46.85,Default,,0,0,0,,Shell 是用首行识别到
Dialogue: 0,0:23:46.85,0:23:50.38,Default,,0,0,0,,需要用 Python 解释器运行这个程序
Dialogue: 0,0:23:51.78,0:23:53.35,Default,,0,0,0,,并且第一行
Dialogue: 0,0:23:53.35,0:23:55.95,Default,,0,0,0,,给了这东西所在的路径
Dialogue: 0,0:23:58.68,0:24:00.18,Default,,0,0,0,,然而,你可能不知道
Dialogue: 0,0:24:00.18,0:24:01.71,Default,,0,0,0,,像不同的设备很可能
Dialogue: 0,0:24:01.71,0:24:04.48,Default,,0,0,0,,会把 Python 放在不同的地方
Dialogue: 0,0:24:04.48,0:24:07.01,Default,,0,0,0,,最好别假设 Python 装在哪儿
Dialogue: 0,0:24:07.05,0:24:09.21,Default,,0,0,0,,其它解释器也是一样
Dialogue: 0,0:24:12.15,0:24:17.65,Default,,0,0,0,,所以你可以做的是调用 `env` 命令
Dialogue: 0,0:24:17.65,0:24:21.61,Default,,0,0,0,,你也可以在 shebang 中给出参数
Dialogue: 0,0:24:21.61,0:24:26.75,Default,,0,0,0,,所以我们现在是在调用 `env` 命令
Dialogue: 0,0:24:26.75,0:24:29.78,Default,,0,0,0,,这是对于绝大多数系统而言的,有一些例外
Dialogue: 0,0:24:29.78,0:24:32.58,Default,,0,0,0,,但是对于绝大多数系统而言它在 `usr/bin`
Dialogue: 0,0:24:32.58,0:24:34.01,Default,,0,0,0,,那儿有很多二进制文件
Dialogue: 0,0:24:34.78,0:24:37.18,Default,,0,0,0,,之后用参数 Python 调用它
Dialogue: 0,0:24:37.88,0:24:39.88,Default,,0,0,0,,它会使用
Dialogue: 0,0:24:39.88,0:24:44.05,Default,,0,0,0,,第一节课提到的 `path` 环境变量
Dialogue: 0,0:24:44.05,0:24:46.45,Default,,0,0,0,,`env` 会在那些路径中找 Python 二进制文件
Dialogue: 0,0:24:46.45,0:24:49.85,Default,,0,0,0,,接着用它去解释这个脚本
Dialogue: 0,0:24:49.85,0:24:51.98,Default,,0,0,0,,这样有更好的可移植性
Dialogue: 0,0:24:51.98,0:24:56.08,Default,,0,0,0,,能让它在我的,你的还有其它的设备上运行
Dialogue: 0,0:25:08.91,0:25:14.18,Default,,0,0,0,,另一件事是 bash 并不是真正现代化的
Dialogue: 0,0:25:14.21,0:25:16.18,Default,,0,0,0,,它好久之前就被开发出来了
Dialogue: 0,0:25:15.98,0:25:18.45,Default,,0,0,0,,有些时候调试起来简直要命
Dialogue: 0,0:25:18.45,0:25:22.85,Default,,0,0,0,,一般来讲,调试的时候直觉会时不时地失效
Dialogue: 0,0:25:22.85,0:25:28.48,Default,,0,0,0,,就像我们之前看到的 `foo` 命令不存在
Dialogue: 0,0:25:28.45,0:25:33.98,Default,,0,0,0,,因此我们在讲义里有一个很高效的工具
Dialogue: 0,0:25:33.98,0:25:36.68,Default,,0,0,0,,这个工具叫做 shellcheck
Dialogue: 0,0:25:36.68,0:25:37.81,Default,,0,0,0,,链接已经放在讲义里了
Dialogue: 0,0:25:37.81,0:25:40.48,Default,,0,0,0,,它能给出 warning 和语法错误
Dialogue: 0,0:25:40.48,0:25:43.45,Default,,0,0,0,,还能指出哪些地方你没正确引用
Dialogue: 0,0:25:43.45,0:25:46.61,Default,,0,0,0,,或者是哪些地方你的空格打错了
Dialogue: 0,0:25:47.31,0:25:49.51,Default,,0,0,0,,举个很简单的例子
Dialogue: 0,0:25:49.51,0:25:53.28,Default,,0,0,0,,`mcd.sh` 这个文件,我们得到了一些错误提示
Dialogue: 0,0:25:53.28,0:25:56.15,Default,,0,0,0,,这些提示说:「嗨!我们惊奇地发现漏掉了一些东西」
Dialogue: 0,0:25:56.15,0:26:00.48,Default,,0,0,0,,这可能导致 `mcd.sh` 在别的系统无法解译成功
Dialogue: 0,0:26:01.15,0:26:04.08,Default,,0,0,0,,并且, `cd` 后面有一个指令
Dialogue: 0,0:26:04.08,0:26:07.41,Default,,0,0,0,,而 `cd` 可能不会被正确执行
Dialogue: 0,0:26:07.41,0:26:08.58,Default,,0,0,0,,这里你可能想用 `cd ... \N\N exit`
Dialogue: 0,0:26:08.58,0:26:14.41,Default,,0,0,0,,之类的东西来代替它
Dialogue: 0,0:26:14.41,0:26:16.28,Default,,0,0,0,,回到这行命令
Dialogue: 0,0:26:16.28,0:26:21.28,Default,,0,0,0,,如果 `cd` 命令没有正确结束
Dialogue: 0,0:26:21.28,0:26:22.91,Default,,0,0,0,,你就不能进入那个文件夹
Dialogue: 0,0:26:22.91,0:26:26.21,Default,,0,0,0,,因为要么你没有权限,要么文件夹不存在
Dialogue: 0,0:26:26.21,0:26:30.78,Default,,0,0,0,,之后程序会给你一个非零的错误码
Dialogue: 0,0:26:30.78,0:26:34.15,Default,,0,0,0,,然后你就会执行 `exit` 命令,停止脚本的运行
Dialogue: 0,0:26:34.15,0:26:38.68,Default,,0,0,0,,而不是在一个不存在的路径继续执行
Dialogue: 0,0:26:40.01,0:26:42.68,Default,,0,0,0,,实际上我还没测试
Dialogue: 0,0:26:42.68,0:26:47.61,Default,,0,0,0,,但是我想我们可以试一下 `example.sh`
Dialogue: 0,0:26:47.61,0:26:50.38,Default,,0,0,0,,这里它告诉我们
Dialogue: 0,0:26:50.38,0:26:54.08,Default,,0,0,0,,应该用另外一种方法检查错误码
Dialogue: 0,0:26:54.08,0:26:58.25,Default,,0,0,0,,原来写的大概不能很好地达到目的
Dialogue: 0,0:27:00.15,0:27:02.65,Default,,0,0,0,,最后一点,我想说的是
Dialogue: 0,0:27:02.65,0:27:07.31,Default,,0,0,0,,当你编写这些 bash 脚本或者函数的时候
Dialogue: 0,0:27:07.31,0:27:09.08,Default,,0,0,0,,写你要运行的 bash 脚本
Dialogue: 0,0:27:09.08,0:27:14.18,Default,,0,0,0,,和写要载入 Shell 的东西
Dialogue: 0,0:27:14.18,0:27:16.31,Default,,0,0,0,,这两者是有区别的
Dialogue: 0,0:27:16.31,0:27:22.58,Default,,0,0,0,,我们将会在命令行环境那一讲里了解这些差别
Dialogue: 0,0:27:22.58,0:27:26.78,Default,,0,0,0,,同时那一讲会用到 `bashrc` 和 `sshrc` 这两种工具
Dialogue: 0,0:27:27.25,0:27:28.75,Default,,0,0,0,,但是,总的来说
Dialogue: 0,0:27:28.75,0:27:31.51,Default,,0,0,0,,如果你做了一些改动,比如你的路径
Dialogue: 0,0:27:31.51,0:27:33.95,Default,,0,0,0,,比方说你 cd 到了一个 bash 脚本
Dialogue: 0,0:27:33.95,0:27:35.98,Default,,0,0,0,,并且你直接运行它
Dialogue: 0,0:27:36.31,0:27:38.85,Default,,0,0,0,,它就不会 `cd` 到 Shell 当前的路径
Dialogue: 0,0:27:39.78,0:27:43.71,Default,,0,0,0,,但是如果你直接通过 Shell 加载 bash 代码
Dialogue: 0,0:27:43.71,0:27:49.15,Default,,0,0,0,,比如你的函数,然后你运行这些函数
Dialogue: 0,0:27:49.15,0:27:51.31,Default,,0,0,0,,这个操作就有相反的副作用
Dialogue: 0,0:27:51.31,0:27:55.28,Default,,0,0,0,,在 Shell 中定义变量也是一样
Dialogue: 0,0:27:58.15,0:28:05.78,Default,,0,0,0,,现在我会讲一些和 Shell 搭配干活不累的工具
Dialogue: 0,0:28:07.15,0:28:09.91,Default,,0,0,0,,第一个昨天已经着重讲过了
Dialogue: 0,0:28:09.91,0:28:14.91,Default,,0,0,0,,怎么去知道 flag 和 command(命令)具体代表什么
Dialogue: 0,0:28:14.91,0:28:18.48,Default,,0,0,0,,就像我现在知道 `ls -l`
Dialogue: 0,0:28:18.48,0:28:21.51,Default,,0,0,0,,会用列表的形式列出文件
Dialogue: 0,0:28:21.51,0:28:26.65,Default,,0,0,0,,或者我运行 `mv -i` 它会给我提示
Dialogue: 0,0:28:27.05,0:28:29.31,Default,,0,0,0,,你现在能用的就是 man 命令
Dialogue: 0,0:28:29.31,0:28:35.18,Default,,0,0,0,,man 命令会给出很多关于命令的信息
Dialogue: 0,0:28:35.18,0:28:39.95,Default,,0,0,0,,比如说在这解释了 `-i` 的作用
Dialogue: 0,0:28:39.95,0:28:42.38,Default,,0,0,0,,这些就是你能做的全部操作
Dialogue: 0,0:28:44.01,0:28:51.48,Default,,0,0,0,,不仅是系统内封装的简单命令
Dialogue: 0,0:28:51.48,0:28:55.85,Default,,0,0,0,,对于一些从网上安装的工具也很方便
Dialogue: 0,0:28:55.85,0:29:00.55,Default,,0,0,0,,例如,如果安装完一些工具
Dialogue: 0,0:29:00.55,0:29:03.05,Default,,0,0,0,,那么 man 要用的文档也安装好了
Dialogue: 0,0:29:03.05,0:29:08.51,Default,,0,0,0,,比如我们要运行这个叫 ripgrep 的工具
Dialogue: 0,0:29:08.51,0:29:11.25,Default,,0,0,0,,它可以用 `rg` 调用
Dialogue: 0,0:29:12.18,0:29:13.71,Default,,0,0,0,,系统里并没有自带这个工具
Dialogue: 0,0:29:13.71,0:29:17.15,Default,,0,0,0,,但是它安装了自己的 man 文档
Dialogue: 0,0:29:17.15,0:29:18.25,Default,,0,0,0,,并且我可以查看
Dialogue: 0,0:29:20.81,0:29:23.78,Default,,0,0,0,,对有些命令来说, man 命令直截了当
Dialogue: 0,0:29:23.78,0:29:26.68,Default,,0,0,0,,但有时,理解 man 调出来的文档也挺头疼
Dialogue: 0,0:29:26.68,0:29:33.41,Default,,0,0,0,,因为它涵盖了这个工具所有的文档和描述
Dialogue: 0,0:29:33.41,0:29:40.01,Default,,0,0,0,,有的时候会有样例,但有的时候没有
Dialogue: 0,0:29:40.01,0:29:45.38,Default,,0,0,0,,比如我经常用的一些优秀工具
Dialogue: 0,0:29:45.38,0:29:47.41,Default,,0,0,0,,像 convert 和 ffmpeg
Dialogue: 0,0:29:47.41,0:29:49.78,Default,,0,0,0,,虽然他们处理图像或视频很优秀
Dialogue: 0,0:29:49.78,0:29:51.85,Default,,0,0,0,,但是他们的 man 文档都是庞然大物
Dialogue: 0,0:29:51.85,0:29:55.95,Default,,0,0,0,,然后有个好东西叫 `tldr`,你可以装一下
Dialogue: 0,0:29:55.95,0:30:02.71,Default,,0,0,0,,然后就会获得关于你如何调用命令的
Dialogue: 0,0:30:02.71,0:30:05.08,Default,,0,0,0,,一些深入浅出的命令示例
Dialogue: 0,0:30:05.08,0:30:06.95,Default,,0,0,0,,你也可以上网搜一下
Dialogue: 0,0:30:06.95,0:30:11.11,Default,,0,0,0,,但这样你就免得去打开浏览器
Dialogue: 0,0:30:11.11,0:30:13.48,Default,,0,0,0,,然后找一堆例子,再返回来
Dialogue: 0,0:30:13.48,0:30:18.88,Default,,0,0,0,,`tldr` 是社区贡献的,确实好用
Dialogue: 0,0:30:18.88,0:30:22.55,Default,,0,0,0,,比如用它查 `ffmpeg`
Dialogue: 0,0:30:22.55,0:30:25.75,Default,,0,0,0,,就有很多经典的例子,格式易于阅读
Dialogue: 0,0:30:25.75,0:30:28.68,Default,,0,0,0,,(但我讲课调了特大号字体,打乱了格式所以不明显)
Dialogue: 0,0:30:30.65,0:30:32.65,Default,,0,0,0,,甚至如 `tar` 这种简单的命令
Dialogue: 0,0:30:32.65,0:30:35.28,Default,,0,0,0,,都有好多 option 要去组合运用
Dialogue: 0,0:30:35.28,0:30:40.98,Default,,0,0,0,,比如这里你可以把两三个 flag 结合
Dialogue: 0,0:30:40.98,0:30:44.58,Default,,0,0,0,,但结合出的效果可能违反直觉
Dialogue: 0,0:30:47.55,0:30:51.95,Default,,0,0,0,,这就是你……要找到更多这样的工具
Dialogue: 0,0:30:53.28,0:30:55.08,Default,,0,0,0,,关于查找的主题,我们再来试一下
Dialogue: 0,0:30:55.08,0:30:58.45,Default,,0,0,0,,怎么去查找文件
Dialogue: 0,0:30:58.45,0:31:01.88,Default,,0,0,0,,你永远可以用 `ls`
Dialogue: 0,0:31:01.88,0:31:04.71,Default,,0,0,0,,比如你可以 `ls project1`
Dialogue: 0,0:31:04.71,0:31:08.51,Default,,0,0,0,,然后一路 `ls` 下去……
Dialogue: 0,0:31:08.51,0:31:16.85,Default,,0,0,0,,但假设,我们已知要找名为 `src` 的文件夹
Dialogue: 0,0:31:16.85,0:31:20.21,Default,,0,0,0,,做这件事有更好的命令
Dialogue: 0,0:31:20.21,0:31:21.65,Default,,0,0,0,,它就是 `find`
Dialogue: 0,0:31:21.65,0:31:25.48,Default,,0,0,0,,`find` 大概是每个 UNIX 系统都有的工具
Dialogue: 0,0:31:25.48,0:31:30.15,Default,,0,0,0,,这个 `find`,我们给他一个……
Dialogue: 0,0:31:32.41,0:31:36.25,Default,,0,0,0,,这里意为,在当前文件夹调用 `find`
Dialogue: 0,0:31:36.25,0:31:39.18,Default,,0,0,0,,记住 `.` 代表当前文件夹
Dialogue: 0,0:31:39.18,0:31:41.95,Default,,0,0,0,,然后我们找名为 `src`
Dialogue: 0,0:31:41.91,0:31:44.85,Default,,0,0,0,,而且类型是个目录的东西
Dialogue: 0,0:31:45.25,0:31:50.38,Default,,0,0,0,,键入这些,它就可以在当前目录递归
Dialogue: 0,0:31:50.38,0:31:52.81,Default,,0,0,0,,查看所有符合规则的文件
Dialogue: 0,0:31:52.81,0:31:55.45,Default,,0,0,0,,或者文件夹,在这个例子里
Dialogue: 0,0:31:55.45,0:31:59.65,Default,,0,0,0,,`find` 也有很多有用的 flag
Dialogue: 0,0:32:00.18,0:32:04.95,Default,,0,0,0,,比如你甚至可以查询指定格式的文件路径
Dialogue: 0,0:32:04.95,0:32:08.58,Default,,0,0,0,,这里(`**`)是指要有几层文件夹
Dialogue: 0,0:32:08.58,0:32:10.25,Default,,0,0,0,,我们并不关心具体是多少个[*]
Dialogue: 0,0:32:10.25,0:32:14.15,Default,,0,0,0,,然后我们想找所有 Python 脚本
Dialogue: 0,0:32:14.15,0:32:16.58,Default,,0,0,0,,也即所有扩展名是 `.py` 的文件
Dialogue: 0,0:32:16.58,0:32:18.71,Default,,0,0,0,,然后要求它们在一个 `test` 文件夹内
Dialogue: 0,0:32:18.71,0:32:19.68,Default,,0,0,0,,然后我们也在确保
Dialogue: 0,0:32:19.68,0:32:20.95,Default,,0,0,0,,虽然确实有点多余,但是
Dialogue: 0,0:32:20.95,0:32:23.95,Default,,0,0,0,,我们也检查它是否为 `F` 类型
Dialogue: 0,0:32:23.95,0:32:25.18,Default,,0,0,0,,`F` 是代表文件
Dialogue: 0,0:32:26.41,0:32:28.21,Default,,0,0,0,,这样就找到了符合的文件
Dialogue: 0,0:32:29.85,0:32:32.35,Default,,0,0,0,,也可以针对非路径和非文件名的查找
Dialogue: 0,0:32:32.35,0:32:34.31,Default,,0,0,0,,运用不同的 flag
Dialogue: 0,0:32:34.78,0:32:39.31,Default,,0,0,0,,比如可以查找被修改过的文件
Dialogue: 0,0:32:39.31,0:32:41.61,Default,,0,0,0,,这里 `-mtime` 代表修改时间
Dialogue: 0,0:32:41.61,0:32:44.21,Default,,0,0,0,,在最近一天被修改过的东西
Dialogue: 0,0:32:44.21,0:32:46.15,Default,,0,0,0,,啊,基本就是这个文件夹的所有东西
Dialogue: 0,0:32:46.15,0:32:48.78,Default,,0,0,0,,打印出了我们刚创建的文件
Dialogue: 0,0:32:48.78,0:32:50.91,Default,,0,0,0,,和先前就有的文件
Dialogue: 0,0:32:50.91,0:32:53.18,Default,,0,0,0,,你甚至可以用其他条件
Dialogue: 0,0:32:53.18,0:32:57.38,Default,,0,0,0,,比如大小,所有者,权限,等等
Dialogue: 0,0:32:58.58,0:33:02.15,Default,,0,0,0,,更强大的是,`find` 不仅查找东西
Dialogue: 0,0:33:02.15,0:33:05.81,Default,,0,0,0,,找到之后还能做别的
Dialogue: 0,0:33:06.18,0:33:14.91,Default,,0,0,0,,我们可以查找所有扩展名是 `.tmp` 的文件
Dialogue: 0,0:33:15.85,0:33:17.68,Default,,0,0,0,,是代表临时文件的扩展名
Dialogue: 0,0:33:18.05,0:33:22.78,Default,,0,0,0,,然后要求 `find` 对于所有这些文件
Dialogue: 0,0:33:22.78,0:33:26.35,Default,,0,0,0,,执行 `rm` 命令
Dialogue: 0,0:33:26.75,0:33:29.88,Default,,0,0,0,,这会对所有这些文件调用 `rm`
Dialogue: 0,0:33:30.38,0:33:33.38,Default,,0,0,0,,我们先不带 `rm` 执行一下
Dialogue: 0,0:33:34.15,0:33:35.58,Default,,0,0,0,,再带着它执行一下
Dialogue: 0,0:33:36.71,0:33:39.75,Default,,0,0,0,,再次根据命令行的设计哲学
Dialogue: 0,0:33:40.88,0:33:42.11,Default,,0,0,0,,看起来无事发生
Dialogue: 0,0:33:42.11,0:33:48.78,Default,,0,0,0,,但我们有 `0` 错误代码,就是有事发生
Dialogue: 0,0:33:48.78,0:33:51.25,Default,,0,0,0,,那就是所有命令执行成功,一切顺利
Dialogue: 0,0:33:51.25,0:33:53.81,Default,,0,0,0,,然后现在再找下这些文件
Dialogue: 0,0:33:53.81,0:33:56.28,Default,,0,0,0,,就找不到了
Dialogue: 0,0:33:58.51,0:34:02.21,Default,,0,0,0,,总体来说, Shell 的另一个好处
Dialogue: 0,0:34:02.21,0:34:04.08,Default,,0,0,0,,就是即便有了这些工具
Dialogue: 0,0:34:04.91,0:34:07.51,Default,,0,0,0,,人们也在创造新的方式
Dialogue: 0,0:34:07.51,0:34:10.31,Default,,0,0,0,,用别的方法开发这些工具
Dialogue: 0,0:34:10.31,0:34:12.15,Default,,0,0,0,,了解一下挺不错的[*]
Dialogue: 0,0:34:12.15,0:34:20.21,Default,,0,0,0,,比如你只想找以 `tmp` 结尾的东西
Dialogue: 0,0:34:20.21,0:34:22.81,Default,,0,0,0,,做这种挺另类的事情
Dialogue: 0,0:34:22.81,0:34:24.48,Default,,0,0,0,,你看这命令其实挺长的
Dialogue: 0,0:34:24.48,0:34:28.11,Default,,0,0,0,,有一个工具叫 `fd`
Dialogue: 0,0:34:28.11,0:34:30.68,Default,,0,0,0,,举个栗子,这命令更短
Dialogue: 0,0:34:30.68,0:34:32.71,Default,,0,0,0,,而且默认使用正则表达式[*]
Dialogue: 0,0:34:32.71,0:34:34.95,Default,,0,0,0,,还会忽略你的 gitfile[*]
Dialogue: 0,0:34:34.95,0:34:36.88,Default,,0,0,0,,你不会想搜到那堆东西的
Dialogue: 0,0:34:38.15,0:34:41.88,Default,,0,0,0,,还有彩色代码和更好的 Unicode 支持……
Dialogue: 0,0:34:41.88,0:34:44.55,Default,,0,0,0,,了解这些工具挺好的
Dialogue: 0,0:34:44.55,0:34:47.51,Default,,0,0,0,,但是重申,核心思想是
Dialogue: 0,0:34:47.51,0:34:51.71,Default,,0,0,0,,你要是知道这些东西存在
Dialogue: 0,0:34:51.71,0:34:56.51,Default,,0,0,0,,就能省去做重复性、无意义工作的时间
Dialogue: 0,0:34:58.61,0:34:59.71,Default,,0,0,0,,另一个要记住的命令是
Dialogue: 0,0:34:59.71,0:35:00.78,Default,,0,0,0,,呃,就比如 `find`
Dialogue: 0,0:35:00.78,0:35:02.78,Default,,0,0,0,,部分同学可能会好奇……
Dialogue: 0,0:35:02.78,0:35:07.68,Default,,0,0,0,,`find` 可能就是遍历目录结构
Dialogue: 0,0:35:07.68,0:35:09.15,Default,,0,0,0,,去找匹配的事物
Dialogue: 0,0:35:09.55,0:35:11.68,Default,,0,0,0,,那我要是每天高强度 `find` 呢?
Dialogue: 0,0:35:11.68,0:35:14.48,Default,,0,0,0,,如果能给整个数据库出来
Dialogue: 0,0:35:14.48,0:35:19.18,Default,,0,0,0,,然后建个索引,不断维护它
Dialogue: 0,0:35:19.18,0:35:21.11,Default,,0,0,0,,岂不美哉
Dialogue: 0,0:35:21.11,0:35:23.71,Default,,0,0,0,,呃,其实大部分 UNIX 系统已经有了
Dialogue: 0,0:35:23.71,0:35:26.68,Default,,0,0,0,,可以用 `locate` 命令
Dialogue: 0,0:35:26.68,0:35:32.31,Default,,0,0,0,,这个 `locate` 会……
Dialogue: 0,0:35:32.31,0:35:39.91,Default,,0,0,0,,它会查找文件系统中具有指定子串的路径
Dialogue: 0,0:35:39.91,0:35:42.85,Default,,0,0,0,,我不知道这行不行……
Dialogue: 0,0:35:42.85,0:35:43.88,Default,,0,0,0,,哦看来可以
Dialogue: 0,0:35:43.88,0:35:49.95,Default,,0,0,0,,我来试试找 `missing-semester`
Dialogue: 0,0:35:52.98,0:35:56.31,Default,,0,0,0,,得等一会,就能找到这些东西
Dialogue: 0,0:35:56.31,0:35:57.15,Default,,0,0,0,,都是在我文件系统里面
Dialogue: 0,0:35:57.15,0:36:02.48,Default,,0,0,0,,因为事先建立了索引,它就会快得多
Dialogue: 0,0:36:02.55,0:36:05.91,Default,,0,0,0,,然后,如果要更新它的话
Dialogue: 0,0:36:05.91,0:36:09.35,Default,,0,0,0,,用这个 `updatedb` 命令
Dialogue: 0,0:36:09.35,0:36:15.51,Default,,0,0,0,,通常由 cron 定期执行来更新数据库。[*]
Dialogue: 0,0:36:16.98,0:36:19.48,Default,,0,0,0,,另外,查找文件是很有门道的
Dialogue: 0,0:36:19.48,0:36:23.68,Default,,0,0,0,,实际上,有时你不关心文件本身
Dialogue: 0,0:36:23.68,0:36:25.78,Default,,0,0,0,,而是文件的内容
Dialogue: 0,0:36:26.78,0:36:25.88,Default,,0,0,0,,这方面可以用前面见过的 `grep` 命令
Dialogue: 0,0:36:25.88,0:36:37.31,Default,,0,0,0,,比如 `grep foobar mcd.sh`
Dialogue: 0,0:36:37.31,0:36:38.18,Default,,0,0,0,,找到了
Dialogue: 0,0:36:38.78,0:36:44.41,Default,,0,0,0,,如果你还是想递归当前目录结构
Dialogue: 0,0:36:44.41,0:36:45.91,Default,,0,0,0,,去查找更多的文件该怎么办
Dialogue: 0,0:36:45.91,0:36:49.05,Default,,0,0,0,,你不会愿意亲手干苦活的
Dialogue: 0,0:36:49.11,0:36:51.05,Default,,0,0,0,,我们可以用 `find` 命令结合 `-exec`
Dialogue: 0,0:36:51.31,0:36:54.81,Default,,0,0,0,,但 `grep` 有一个大写 `-R` 的 flag
Dialogue: 0,0:36:54.81,0:37:00.15,Default,,0,0,0,,是可以找遍整个目录的
Dialogue: 0,0:37:00.15,0:37:02.18,Default,,0,0,0,,啊,应该是这样儿
Dialogue: 0,0:37:02.91,0:37:04.11,Default,,0,0,0,,它告诉我们,噢
Dialogue: 0,0:37:04.11,0:37:07.68,Default,,0,0,0,,`example.sh` 中有包含 `foobar` 的行
Dialogue: 0,0:37:07.68,0:37:09.48,Default,,0,0,0,,在这三个行的位置都有
Dialogue: 0,0:37:09.48,0:37:11.61,Default,,0,0,0,,并且这两个位置也有 `foobar`
Dialogue: 0,0:37:14.35,0:37:15.95,Default,,0,0,0,,这个挺省事的
Dialogue: 0,0:37:15.95,0:37:20.45,Default,,0,0,0,,主要是当你记得你用一些程序语言
Dialogue: 0,0:37:20.45,0:37:22.75,Default,,0,0,0,,写了一些代码的时候
Dialogue: 0,0:37:22.75,0:37:25.55,Default,,0,0,0,,你知道它就在你文件系统的某处躺着
Dialogue: 0,0:37:25.55,0:37:27.01,Default,,0,0,0,,但你就是想不起来
Dialogue: 0,0:37:27.01,0:37:29.25,Default,,0,0,0,,用这招就可以快速搜索
Dialogue: 0,0:37:29.51,0:37:33.28,Default,,0,0,0,,比如我可以快速搜索草稿文件夹里
Dialogue: 0,0:37:35.78,0:37:45.65,Default,,0,0,0,,所有我用了 `request` 库的 Python 代码
Dialogue: 0,0:37:46.01,0:37:46.98,Default,,0,0,0,,如果我执行命令
Dialogue: 0,0:37:46.98,0:37:53.35,Default,,0,0,0,,就能查到这些文件,精确到匹配的行
Dialogue: 0,0:37:53.35,0:37:56.45,Default,,0,0,0,,比起用 `grep`,虽然它挺好
Dialogue: 0,0:37:56.45,0:37:59.61,Default,,0,0,0,,你也可以……我用了 `ripgrep`
Dialogue: 0,0:37:59.85,0:38:04.25,Default,,0,0,0,,原理是一样的,但是它也是
Dialogue: 0,0:38:04.25,0:38:06.11,Default,,0,0,0,,加了亿点点细节
Dialogue: 0,0:38:06.11,0:38:12.95,Default,,0,0,0,,比如代码彩色和文件处理啥的
Dialogue: 0,0:38:12.95,0:38:15.18,Default,,0,0,0,,也有 Unicode 支持
Dialogue: 0,0:38:15.45,0:38:17.15,Default,,0,0,0,,而且跑的还快
Dialogue: 0,0:38:17.15,0:38:21.25,Default,,0,0,0,,所以它没为了这些花招拖慢速度
Dialogue: 0,0:38:23.31,0:38:25.31,Default,,0,0,0,,还有很多有用的 flag
Dialogue: 0,0:38:25.31,0:38:30.61,Default,,0,0,0,,比如说你想,哦,我想要点上下文
Dialogue: 0,0:38:33.15,0:38:37.11,Default,,0,0,0,,这样就是结果附近的五行
Dialogue: 0,0:38:37.35,0:38:40.78,Default,,0,0,0,,你就能知道那个 `import` 大概在哪
Dialogue: 0,0:38:40.78,0:38:43.08,Default,,0,0,0,,它周围都是什么代码
Dialogue: 0,0:38:43.18,0:38:44.51,Default,,0,0,0,,这里找这个 `import` 不怎么实用
Dialogue: 0,0:38:44.51,0:38:47.51,Default,,0,0,0,,但是比如,你要查你在哪调用了函数
Dialogue: 0,0:38:47.51,0:38:51.08,Default,,0,0,0,,它就很给力
Dialogue: 0,0:38:52.08,0:38:59.18,Default,,0,0,0,,我们也可以搜索,比如说
Dialogue: 0,0:38:59.18,0:39:02.58,Default,,0,0,0,,一个更高级的用法
Dialogue: 0,0:39:02.58,0:39:09.48,Default,,0,0,0,,解释一下,`-u` 是不忽略隐藏文件[*]
Dialogue: 0,0:39:09.48,0:39:15.78,Default,,0,0,0,,有时候你想忽略隐藏文件
Dialogue: 0,0:39:15.78,0:39:19.81,Default,,0,0,0,,但如果你想查找配置(config)文件
Dialogue: 0,0:39:19.81,0:39:21.38,Default,,0,0,0,,它们大多是默认隐藏的,这样子
Dialogue: 0,0:39:21.38,0:39:24.95,Default,,0,0,0,,然后,这里不是打印匹配内容
Dialogue: 0,0:39:25.35,0:39:27.55,Default,,0,0,0,,而我们要求它,呃,这大概是
Dialogue: 0,0:39:27.55,0:39:30.98,Default,,0,0,0,,我觉得 `grep` 做不到的
Dialogue: 0,0:39:30.98,0:39:34.38,Default,,0,0,0,,就是,我要你打印出所有
Dialogue: 0,0:39:34.38,0:39:37.35,Default,,0,0,0,,不匹配这个模式的内容
Dialogue: 0,0:39:37.85,0:39:40.28,Default,,0,0,0,,这么做可能挺奇怪的
Dialogue: 0,0:39:40.28,0:39:41.75,Default,,0,0,0,,接着往下看……
Dialogue: 0,0:39:41.75,0:39:43.21,Default,,0,0,0,,这里这个模式(pattern)是一个
Dialogue: 0,0:39:43.65,0:39:45.15,Default,,0,0,0,,小巧的正则表达式
Dialogue: 0,0:39:45.41,0:39:49.91,Default,,0,0,0,,意思是,匹配行首有 `#!` 的内容
Dialogue: 0,0:39:50.68,0:39:51.45,Default,,0,0,0,,这是个 `shebang`
Dialogue: 0,0:39:51.45,0:39:57.08,Default,,0,0,0,,也就是说我们在搜索没有 shebang 的文件
Dialogue: 0,0:39:57.41,0:40:01.31,Default,,0,0,0,,这里还给了一个 `-t sh` 是说
Dialogue: 0,0:40:01.31,0:40:03.55,Default,,0,0,0,,只搜索 `.sh` (后缀名)的文件
Dialogue: 0,0:40:03.55,0:40:07.78,Default,,0,0,0,,因为实际来讲 Python 或者文本文件
Dialogue: 0,0:40:07.78,0:40:08.91,Default,,0,0,0,,少了 shebang 也没问题
Dialogue: 0,0:40:09.35,0:40:10.18,Default,,0,0,0,,这里它告诉我们
Dialogue: 0,0:40:10.18,0:40:12.58,Default,,0,0,0,,「哦,`mcd.sh` 明显少了个 shebang」
Dialogue: 0,0:40:14.91,0:40:18.45,Default,,0,0,0,,我们还可以……它有一些好用的 flag
Dialogue: 0,0:40:18.45,0:40:21.11,Default,,0,0,0,,比如加上这个 `--stats` flag
Dialogue: 0,0:40:29.01,0:40:31.51,Default,,0,0,0,,它也会得到这些结果
Dialogue: 0,0:40:31.51,0:40:35.15,Default,,0,0,0,,不过它还会告诉我们
Dialogue: 0,0:40:35.15,0:40:38.28,Default,,0,0,0,,比如成功匹配了多少行
Dialogue: 0,0:40:38.28,0:40:41.05,Default,,0,0,0,,查找了多少行多少文件
Dialogue: 0,0:40:41.05,0:40:42.58,Default,,0,0,0,,打印了多少 byte,等等
Dialogue: 0,0:40:44.08,0:40:47.41,Default,,0,0,0,,类似 `fd` 这种,有时候单会一个工具
Dialogue: 0,0:40:48.81,0:40:50.75,Default,,0,0,0,,其实不是很好
Dialogue: 0,0:40:50.75,0:40:54.28,Default,,0,0,0,,实际上有很多类似 `ripgrep` 的工具
Dialogue: 0,0:40:54.28,0:40:58.38,Default,,0,0,0,,比如 `ack`,也是 `grep` 一个替代
Dialogue: 0,0:40:58.78,0:41:03.11,Default,,0,0,0,,还有 `ag`,那个“银子”搜索器[*]
Dialogue: 0,0:41:03.11,0:41:05.78,Default,,0,0,0,,这些基本都是可替换的
Dialogue: 0,0:41:05.78,0:41:07.55,Default,,0,0,0,,有可能你用某个操作系统
Dialogue: 0,0:41:07.55,0:41:08.81,Default,,0,0,0,,发现它有某一个,没有另一个
Dialogue: 0,0:41:08.81,0:41:13.38,Default,,0,0,0,,只要知道你可以用这些工具就行
Dialogue: 0,0:41:14.75,0:41:17.51,Default,,0,0,0,,最后我想讲讲,怎么去做一些
Dialogue: 0,0:41:17.51,0:41:19.38,Default,,0,0,0,,不是去找文件或者代码
Dialogue: 0,0:41:19.38,0:41:24.28,Default,,0,0,0,,而是找一些已经执行过的命令
Dialogue: 0,0:41:26.85,0:41:30.58,Default,,0,0,0,,首先,显然可以用上箭头
Dialogue: 0,0:41:31.11,0:41:34.91,Default,,0,0,0,,慢慢儿翻你的历史记录
Dialogue: 0,0:41:34.91,0:41:37.58,Default,,0,0,0,,你可能也觉得,这不是很有效率
Dialogue: 0,0:41:37.58,0:41:43.05,Default,,0,0,0,,所以 bash 有一些更简单的方法
Dialogue: 0,0:41:43.35,0:41:44.58,Default,,0,0,0,,有个 `history` 命令
Dialogue: 0,0:41:44.58,0:41:45.75,Default,,0,0,0,,它会打印出你的命令历史记录
Dialogue: 0,0:41:46.01,0:41:49.25,Default,,0,0,0,,这里我用的 zsh,所以只会打印一部分
Dialogue: 0,0:41:49.25,0:41:53.58,Default,,0,0,0,,如果我想从开头全打印出来
Dialogue: 0,0:41:53.81,0:41:58.35,Default,,0,0,0,,这就不管是啥,都给打印出来了
Dialogue: 0,0:41:58.38,0:42:00.75,Default,,0,0,0,,因为这记录挺多的
Dialogue: 0,0:42:00.75,0:42:04.85,Default,,0,0,0,,比如我只关心用了 `convert` 的命令
Dialogue: 0,0:42:04.85,0:42:08.91,Default,,0,0,0,,它把某种类型的文件转到另一种
Dialogue: 0,0:42:08.91,0:42:11.31,Default,,0,0,0,,呃 抱歉,是图片类型(而非所有文件)
Dialogue: 0,0:42:11.31,0:42:15.08,Default,,0,0,0,,这里就是所有的结果
Dialogue: 0,0:42:15.08,0:42:18.08,Default,,0,0,0,,所有匹配上这个子字符串的
Dialogue: 0,0:42:21.28,0:42:24.81,Default,,0,0,0,,更进一步,基本上所有 Shell
Dialogue: 0,0:42:24.81,0:42:27.45,Default,,0,0,0,,默认都会把 `Ctrl`+`R` 这个组合键
Dialogue: 0,0:42:27.45,0:42:29.55,Default,,0,0,0,,设成(按执行时间)倒序搜索(backward search)
Dialogue: 0,0:42:29.55,0:42:31.25,Default,,0,0,0,,这里我们打开倒序搜索
Dialogue: 0,0:42:31.25,0:42:33.15,Default,,0,0,0,,然后输入 `convert`
Dialogue: 0,0:42:33.15,0:42:36.15,Default,,0,0,0,,就会找到与之匹配的命令
Dialogue: 0,0:42:36.15,0:42:38.41,Default,,0,0,0,,如果我们接着按 `Ctrl`+`R`
Dialogue: 0,0:42:38.41,0:42:41.31,Default,,0,0,0,,就会倒着往前搜索匹配的命令
Dialogue: 0,0:42:41.31,0:42:45.15,Default,,0,0,0,,也可以重新执行命令
Dialogue: 0,0:42:45.91,0:42:50.55,Default,,0,0,0,,另一个相关的是
Dialogue: 0,0:42:50.55,0:42:53.28,Default,,0,0,0,,你可以用这个叫 `fzf` 的高级货
Dialogue: 0,0:42:53.28,0:42:55.98,Default,,0,0,0,,它就是一个模糊搜索工具
Dialogue: 0,0:42:55.98,0:43:00.35,Default,,0,0,0,,像是一个交互式的 `grep`
Dialogue: 0,0:43:02.11,0:43:06.25,Default,,0,0,0,,举个栗子,先 `cat` 一下我们这个
Dialogue: 0,0:43:06.25,0:43:09.25,Default,,0,0,0,,`example.sh`
Dialogue: 0,0:43:09.61,0:43:11.51,Default,,0,0,0,,就会打印到标准输出
Dialogue: 0,0:43:11.51,0:43:13.51,Default,,0,0,0,,然后我们用管道连到 `fzf` 上
Dialogue: 0,0:43:13.51,0:43:15.35,Default,,0,0,0,,先是显示出所有行
Dialogue: 0,0:43:15.35,0:43:19.95,Default,,0,0,0,,然后可以实时地输入要找的字符串
Dialogue: 0,0:43:20.98,0:43:23.71,Default,,0,0,0,,`fzf` 有一个好,就是
Dialogue: 0,0:43:23.71,0:43:26.65,Default,,0,0,0,,如果你打开默认绑定,它会绑定到
Dialogue: 0,0:43:26.65,0:43:33.68,Default,,0,0,0,,Shell 的 `Ctrl`+`R` 执行上
Dialogue: 0,0:43:33.68,0:43:38.58,Default,,0,0,0,,然后你就可以动态的查看
Dialogue: 0,0:43:38.58,0:43:41.51,Default,,0,0,0,,历史记录里转换 `favicon` 的命令
Dialogue: 0,0:43:42.25,0:43:44.88,Default,,0,0,0,,它还是模糊匹配的
Dialogue: 0,0:43:44.88,0:43:46.88,Default,,0,0,0,,比起在 `grep` 里默认你得
Dialogue: 0,0:43:46.88,0:43:52.35,Default,,0,0,0,,写正则表达式才能搞定这种情况
Dialogue: 0,0:43:52.35,0:43:54.88,Default,,0,0,0,,这里就只打 `convert` 和 `favicon`
Dialogue: 0,0:43:54.88,0:43:57.65,Default,,0,0,0,,它就能尝试最优的扫描策略
Dialogue: 0,0:43:57.65,0:43:59.81,Default,,0,0,0,,在给定的行里匹配出来
Dialogue: 0,0:44:02.18,0:44:04.78,Default,,0,0,0,,最后就是这个工具
Dialogue: 0,0:44:04.78,0:44:06.91,Default,,0,0,0,,你们已经看到了我一直用的
Dialogue: 0,0:44:06.91,0:44:09.35,Default,,0,0,0,,免去打那些又臭又长的命令
Dialogue: 0,0:44:09.35,0:44:12.51,Default,,0,0,0,,就是这个历史记录子串查找[*]
Dialogue: 0,0:44:12.51,0:44:15.91,Default,,0,0,0,,当我在 Shell 里输入的时候
Dialogue: 0,0:44:15.91,0:44:19.48,Default,,0,0,0,,(呃,这个忘记介绍了)
Dialogue: 0,0:44:19.48,0:44:22.71,Default,,0,0,0,,(就是 fish,我以为我提到过的)[*]
Dialogue: 0,0:44:22.71,0:44:25.05,Default,,0,0,0,,fish 和 zsh 都有很好的实现
Dialogue: 0,0:44:26.18,0:44:28.68,Default,,0,0,0,,它们可以,当你打字的时候
Dialogue: 0,0:44:28.68,0:44:31.91,Default,,0,0,0,,动态搜索你的历史记录
Dialogue: 0,0:44:31.91,0:44:34.41,Default,,0,0,0,,找到前缀相符的一个命令
Dialogue: 0,0:44:35.65,0:44:43.41,Default,,0,0,0,,如果匹配的那条不相符了也会变化
Dialogue: 0,0:44:43.41,0:44:45.35,Default,,0,0,0,,如果你按一下右箭头
Dialogue: 0,0:44:45.35,0:44:48.91,Default,,0,0,0,,就能选中这个命令,就可以重新执行
Dialogue: 0,0:45:06.95,0:45:08.95,Default,,0,0,0,,我们已经见识了一大堆东西了
Dialogue: 0,0:45:08.95,0:45:11.55,Default,,0,0,0,,我觉得我还剩下几分钟
Dialogue: 0,0:45:11.55,0:45:15.68,Default,,0,0,0,,我打算讲几个工具
Dialogue: 0,0:45:15.68,0:45:19.98,Default,,0,0,0,,可以快速列出目录和定位目录的
Dialogue: 0,0:45:19.98,0:45:30.38,Default,,0,0,0,,确实可以用 `-R` 递归列出目录结构
Dialogue: 0,0:45:30.38,0:45:32.78,Default,,0,0,0,,但是这样不是很好受
Dialogue: 0,0:45:32.78,0:45:35.25,Default,,0,0,0,,呃 我轻易读不懂这一堆鬼玩意
Dialogue: 0,0:45:36.78,0:45:40.11,Default,,0,0,0,,有个叫 `tree` 的工具可以
Dialogue: 0,0:45:40.11,0:45:45.78,Default,,0,0,0,,用比较友好的格式打印这些东西
Dialogue: 0,0:45:45.78,0:45:47.58,Default,,0,0,0,,它也会用彩色文本,基于……
Dialogue: 0,0:45:47.58,0:45:49.28,Default,,0,0,0,,就比如说 `foo` 是蓝的
Dialogue: 0,0:45:49.28,0:45:51.65,Default,,0,0,0,,代表是个目录
Dialogue: 0,0:45:51.65,0:45:54.88,Default,,0,0,0,,这个是红的,因为有执行权限
Dialogue: 0,0:45:55.68,0:45:57.58,Default,,0,0,0,,我们还可以再深入些
Dialogue: 0,0:45:57.58,0:46:01.88,Default,,0,0,0,,有些好用的,比如最近有个
Dialogue: 0,0:46:01.88,0:46:04.45,Default,,0,0,0,,`broot`,也是做差不多的事情
Dialogue: 0,0:46:04.45,0:46:08.38,Default,,0,0,0,,但是比起列出所有文件
Dialogue: 0,0:46:08.38,0:46:09.91,Default,,0,0,0,,比如说在 `bar` 里我们有
Dialogue: 0,0:46:09.91,0:46:11.75,Default,,0,0,0,,`a` 一直到 `j` 这些文件
Dialogue: 0,0:46:11.75,0:46:14.35,Default,,0,0,0,,它会提示「还有更多文件,未列出」
Dialogue: 0,0:46:15.45,0:46:18.21,Default,,0,0,0,,我还可以开始输入,它也会
Dialogue: 0,0:46:18.21,0:46:21.71,Default,,0,0,0,,模糊匹配这些文件
Dialogue: 0,0:46:21.71,0:46:24.75,Default,,0,0,0,,我可以快速的选择和定位
Dialogue: 0,0:46:25.41,0:46:27.01,Default,,0,0,0,,所以还是说
Dialogue: 0,0:46:27.01,0:46:30.38,Default,,0,0,0,,知道有这些东西挺好
Dialogue: 0,0:46:30.38,0:46:36.01,Default,,0,0,0,,你就不会浪费太多时间
Dialogue: 0,0:46:38.21,0:46:40.45,Default,,0,0,0,,还有就是,我记得我装了
Dialogue: 0,0:46:40.45,0:46:45.01,Default,,0,0,0,,也是一个,你可能希望你的操作系统该带的
Dialogue: 0,0:46:45.01,0:46:48.51,Default,,0,0,0,,比如 Nautilus 或者 mac 的访达[*]
Dialogue: 0,0:46:48.51,0:46:54.78,Default,,0,0,0,,有一个交互式的界面
Dialogue: 0,0:46:54.78,0:46:59.15,Default,,0,0,0,,你可以用箭头定向,浏览
Dialogue: 0,0:47:00.05,0:47:01.11,Default,,0,0,0,,这也许有点过犹不及了
Dialogue: 0,0:47:01.11,0:47:04.11,Default,,0,0,0,,但如果在里面走一圈
Dialogue: 0,0:47:04.11,0:47:07.85,Default,,0,0,0,,你能够很快速地理解目录结构
Dialogue: 0,0:47:08.11,0:47:09.98,Default,,0,0,0,,而且基本所有这些工具
Dialogue: 0,0:47:09.98,0:47:12.98,Default,,0,0,0,,去看看选项列表
Dialogue: 0,0:47:12.98,0:47:15.71,Default,,0,0,0,,它都可以让你编辑和复制文件什么的
Dialogue: 0,0:47:17.88,0:47:19.81,Default,,0,0,0,,最后附加一项就是你怎么
Dialogue: 0,0:47:19.81,0:47:21.31,Default,,0,0,0,,去到一个位置
Dialogue: 0,0:47:21.31,0:47:23.01,Default,,0,0,0,,我们有 `cd`,挺好用的
Dialogue: 0,0:47:23.01,0:47:28.18,Default,,0,0,0,,可以让你进入很多地方
Dialogue: 0,0:47:28.18,0:47:30.21,Default,,0,0,0,,但是如果你能快速去到
Dialogue: 0,0:47:30.21,0:47:36.88,Default,,0,0,0,,你最近访问的,或者经常访问的地方
Dialogue: 0,0:47:36.88,0:47:38.28,Default,,0,0,0,,还是挺美妙的
Dialogue: 0,0:47:38.78,0:47:42.15,Default,,0,0,0,,这个有挺多实现方式的
Dialogue: 0,0:47:42.15,0:47:44.21,Default,,0,0,0,,你可以考虑,哦,我可以做标签
Dialogue: 0,0:47:44.21,0:47:46.81,Default,,0,0,0,,我可以在 Shell 里设置别名
Dialogue: 0,0:47:46.81,0:47:49.05,Default,,0,0,0,,这个挑时间会讲
Dialogue: 0,0:47:49.05,0:47:50.41,Default,,0,0,0,,还有符号链接……
Dialogue: 0,0:47:51.31,0:47:53.05,Default,,0,0,0,,不过当前来说
Dialogue: 0,0:47:53.05,0:47:55.48,Default,,0,0,0,,写了这些工具的程序员们
Dialogue: 0,0:47:55.48,0:47:59.31,Default,,0,0,0,,他们搞出了一个特别好的方式
Dialogue: 0,0:48:00.51,0:48:03.55,Default,,0,0,0,,有一个是用叫「autojump」的项目……
Dialogue: 0,0:48:03.55,0:48:05.68,Default,,0,0,0,,……也许我这里没有……?
Dialogue: 0,0:48:14.91,0:48:17.68,Default,,0,0,0,,呃啊。没事儿,我会在讲到
Dialogue: 0,0:48:17.68,0:48:19.15,Default,,0,0,0,,命令行环境的时候再讲
Dialogue: 0,0:48:22.11,0:48:25.68,Default,,0,0,0,,我觉得大概是我禁用了 `Ctrl`+`R`
Dialogue: 0,0:48:25.68,0:48:29.05,Default,,0,0,0,,影响到了脚本的其他部分
Dialogue: 0,0:48:29.48,0:48:31.58,Default,,0,0,0,,我认为现在如果任何人
Dialogue: 0,0:48:31.58,0:48:34.08,Default,,0,0,0,,有相关问题的话
Dialogue: 0,0:48:34.08,0:48:35.95,Default,,0,0,0,,如果有东西我没讲清楚的话
Dialogue: 0,0:48:35.95,0:48:37.91,Default,,0,0,0,,我非常乐于解答
Dialogue: 0,0:48:37.91,0:48:42.95,Default,,0,0,0,,没有的话,我们搞了一堆习题
Dialogue: 0,0:48:42.95,0:48:44.98,Default,,0,0,0,,差不多都是这些主题的
Dialogue: 0,0:48:44.98,0:48:46.71,Default,,0,0,0,,我们鼓励你去做一下
Dialogue: 0,0:48:46.71,0:48:49.28,Default,,0,0,0,,以及办公时间来找我们
Dialogue: 0,0:48:49.28,0:48:51.48,Default,,0,0,0,,我们可以帮你搞明白习题
Dialogue: 0,0:48:51.48,0:48:54.11,Default,,0,0,0,,或者没说清楚的一些 bash 的细节