-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path0320bash.html
2809 lines (2808 loc) · 240 KB
/
0320bash.html
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
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Author" content="VBird, 鸟哥">
<meta name="Description" content="学习 bash shell">
<title>鸟哥的 Linux 私房菜 -- 第十章、认识与学习BASH</title>
<style type="text/css">
</style>
<link href="./vbird_files/style_2013.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="tablearea">
<div class="mainarea">
<div class="block1">
<!-- 本文的档头部分 -->
<h1>第十章、认识与学习BASH</h1>
<div style="text-align:right">
<span class="text_history">最近更新日期:2015/07/09</span>
</div>
<!-- 本文的档头部分 -->
<div class="abstract">
<p>在 Linux 的环境下,如果你不懂 bash 是什么,那么其他的东西就不用学了!因为前面几章我们使用终端机下达指令的方式,
就是透过 bash 的环境来处理的喔!所以说,他很重要吧!bash 的东西非常的多,包括变量的设置与使用、
bash 操作环境的建置、数据流重导向的功能,还有那好用的管线命令!好好清一清脑门,准备用功去啰~ ^_^
这个章节几乎是所有指令列模式 (command line) 与未来主机维护与管理的重要基础,一定要好好仔细的阅读喔!</p>
</div>
<!-- 本文的链接区部分 -->
<div class="links">
<ul>
<li><a href="0320bash.html#bash">10.1 认识 BASH 这个 Shell</a>
<ul>
<li><a href="0320bash.html#bash_what">10.1.1 硬件、核心与 Shell</a></li>
<li><a href="0320bash.html#bash_why">10.1.2 为何要学文本接口的 shell</a></li>
<li><a href="0320bash.html#bash_shells">10.1.3 系统的合法 shell 与 /etc/shells 功能</a></li>
<li><a href="0320bash.html#bash_bash">10.1.4 Bash shell 的功能</a></li>
<li><a href="0320bash.html#bash_type">10.1.5 查找指令是否为 Bash shell 的内置命令: type</a></li>
<li><a href="0320bash.html#bash_command">10.1.6 指令的下达与快速编辑按钮</a></li>
</ul></li>
<li><a href="0320bash.html#variable">10.2 Shell 的变量功能</a>
<ul>
<li><a href="0320bash.html#variable_var">10.2.1 什么是变量?</a></li>
<li><a href="0320bash.html#variable_echo">10.2.2 变量的取用与设置</a>:<a href="0320bash.html#echo">echo</a>,
<a href="0320bash.html#variable_rule">变量设置规则</a>, <a href="0320bash.html#unset">unset</a></li>
<li><a href="0320bash.html#variable_environ">10.2.3 环境变量的功能</a>:
<a href="0320bash.html#env">env 与常见环境变量说明</a>,
<a href="0320bash.html#set">set</a>, <a href="0320bash.html#export">export</a></li>
<li><a href="0320bash.html#variable_locale">10.2.4 影响显示结果的语系变量 (locale)</a></li>
<li><a href="0320bash.html#variable_range">10.2.5 变量的有效范围</a></li>
<li><a href="0320bash.html#variable_read">10.2.6 变量键盘读取、数组与声明</a>: <a href="0320bash.html#read">read</a>,
<a href="0320bash.html#declare">declare</a>, <a href="0320bash.html#array">array</a></li>
<li><a href="0320bash.html#variable_ulimit">10.2.7 与文件系统及进程的限制关系: ulimit</a></li>
<li><a href="0320bash.html#variable_other">10.2.8 变量内容的删除、取代与替换 (Optional):</a>,
<a href="0320bash.html#variable_other_replace">删除与取代</a>,
<a href="0320bash.html#variable_other_re">测试与替换</a></li>
</ul></li>
<li><a href="0320bash.html#alias_history">10.3 命令别名与历史命令</a>
<ul>
<li><a href="0320bash.html#alias">10.3.1 命令别名设置: alias, unalias</a></li>
<li><a href="0320bash.html#history">10.3.2 历史命令: history, HISTSIZE</a></li>
</ul></li>
<li><a href="0320bash.html#settings">10.4 Bash shell 的操作环境</a>
<ul>
<li><a href="0320bash.html#settings_path">10.4.1 路径与指令搜索顺序</a></li>
<li><a href="0320bash.html#settings_issue">10.4.2 bash 的进站与欢迎消息: /etc/issue, /etc/motd</a></li>
<li><a href="0320bash.html#settings_bashrc">10.4.3 环境设置档:</a>
<a href="0320bash.html#settings_bashrc_shell">login, non-login shell</a>,
<a href="0320bash.html#settings_bashrc_profile">/etc/profile</a>,
<a href="0320bash.html#settings_bashrc_bash_profile">~/.bash_profile</a>,
<a href="0320bash.html#source">source</a>,
<a href="0320bash.html#settings_bashrc_bashrc">~/.bashrc</a></li>
<li><a href="0320bash.html#settings_set">10.4.4 终端机的环境设置: stty, set</a></li>
<li><a href="0320bash.html#settings_wildcard">10.4.5 通配符与特殊符号</a></li>
</ul></li>
<li><a href="0320bash.html#redirect">10.5 数据流重导向 (Redirection)</a>
<ul>
<li><a href="0320bash.html#redirect_redirect">10.5.1 何谓数据流重导向?</a></li>
<li><a href="0320bash.html#redirect_com">10.5.2 命令运行的判断依据: ; , &&, ||</a></li>
</ul></li>
<li><a href="0320bash.html#pipe">10.6 管线命令 (pipe)</a>
<ul>
<li><a href="0320bash.html#pipe_1">10.6.1 截取命令:</a> <a href="0320bash.html#cut">cut</a>, <a href="0320bash.html#grep">grep</a></li>
<li><a href="0320bash.html#pipe_2">10.6.2 排序命令:</a> <a href="0320bash.html#sort">sort</a>, <a href="0320bash.html#uniq">uniq</a>,
<a href="0320bash.html#wc">wc</a></li>
<li><a href="0320bash.html#pipe_3">10.6.3 双向重导向:</a> <a href="0320bash.html#tee">tee</a></li>
<li><a href="0320bash.html#pipe_4">10.6.4 字符转换命令:</a> <a href="0320bash.html#tr">tr</a>, <a href="0320bash.html#col">col</a>,
<a href="0320bash.html#join">join</a>, <a href="0320bash.html#paste">paste</a>, <a href="0320bash.html#expand">expand</a></li>
<li><a href="0320bash.html#split">10.6.5 分割命令: split</a></li>
<li><a href="0320bash.html#xargs">10.6.6 参数代换: xargs</a></li>
<li><a href="0320bash.html#pipe_7">10.6.7 关于减号 - 的用途</a></li>
</ul></li>
<li><a href="0320bash.html#hint">10.7 重点回顾</a></li>
<li><a href="0320bash.html#ex">10.8 本章习题</a></li>
<li><a href="0320bash.html#reference">10.9 参考数据与延伸阅读</a></li>
</ul>
</div>
</div>
<!-- 本文的正式部分 -->
<a id="bash"></a>
<div class="block1">
<h2>10.1 认识 BASH 这个 Shell</h2>
<p>我们在<a href="0110whatislinux.html">第一章 Linux 是什么</a>当中提到了:
管理整个电脑硬件的其实是操作系统的核心 (kernel),这个核心是需要被保护的!
所以我们一般用户就只能透过 shell 来跟核心沟通,以让核心达到我们所想要达到的工作。
那么系统有多少 shell 可用呢?为什么我们要使用 bash 啊?底下分别来谈一谈喔!</p>
<a id="bash_what"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.1.1 硬件、核心与 Shell</h2>
<p>这应该是个蛮有趣的话题:『<span class="text_import2">什么是 Shell</span> 』?相信只要摸过电脑,对于操作系统 (不论是 Linux 、 Unix 或者是 Windows)
有点概念的朋友们大多听过这个名词,因为只要有『操作系统』那么就离不开
Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下电脑的运作状况吧!
举个例子来说:<span class="text_import2">当你要电脑传输出来『音乐』的时候,你的电脑需要什么东西呢</span>?</p>
<ol>
<li>硬件:当然就是需要你的硬件有『声卡芯片』这个配备,否则怎么会有声音;</li>
<li>核心管理:操作系统的核心可以支持这个芯片组,当然还需要提供芯片的驱动程序啰;</li>
<li>应用程序:需要用户 (就是你) 输入发生声音的指令啰!</li>
</ol>
<p>这就是基本的一个输出声音所需要的步骤!也就是说,你必须要『输入』一个指令之后,
『硬件』才会透过你下达的指令来工作!那么硬件如何知道你下达的指令呢?那就是
kernel (核心) 的控制工作了!也就是说,<span class="text_import2">我们必须要透过『
Shell 』将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作</span>!
基本上,我们可以透过底下这张图来说明一下:</p>
<a id="fig10.1.1"></a>
<div style="text-align:center; margin: 0 auto 0 auto; "><img src="./vbird_files/0320bash_1.jpg" alt="硬件、核心与用户的相关性图标" title="硬件、核心与用户的相关性图标" style="border: 1px solid black; padding: 10px "></div>
<div style="text-align: center;">图10.1.1、硬件、核心与用户的相关性图标</div>
<p>我们在<a href="0105computers.html#program_os">第零章内的操作系统小节</a>曾经提到过,
<span class="text_import2">操作系统其实是一组软件,由于这组软件在控制整个硬件与管理系统的活动监测,
如果这组软件能被用户随意的操作,若用户应用不当,将会使得整个系统崩溃</span>!因为操作系统管理的就是整个硬件功能嘛!
所以当然不能够随便被一些没有管理能力的终端用户随意使用啰!</p>
<p>但是我们总是需要让用户操作系统的,所以就有了在操作系统上面发展的应用程序啦!用户可以透过应用程序来指挥核心,
让核心达成我们所需要的硬件任务!如果考虑如<a href="0105computers/os_01.gif" target="_blank">第零章所提供的操作系统图标(图0.4.2)</a>,
我们可以发现应用程序其实是在最外层,就如同鸡蛋的外壳一样,因此这个咚咚也就被称呼为壳程序 (shell) 啰!</p>
<p>其实壳程序的功能只是提供用户操作系统的一个接口,因此这个壳程序需要可以调用其他软件才好。
我们在第四章到第九章提到过很多指令,包括 man, chmod, chown, vi, fdisk, mkfs 等等指令,这些指令都是独立的应用程序,
但是我们可以透过壳程序 (就是指令列模式) 来操作这些应用程序,让这些应用程序调用核心来运作所需的工作哩!
这样对于壳程序是否有了一定的概念了?</p>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 也就是说,只要能够操作应用程序的接口都能够称为壳程序。狭义的壳程序指的是指令列方面的软件,包括本章要介绍的 bash 等。
广义的壳程序则包括图形接口的软件!因为图形接口其实也能够操作各种应用程序来调用核心工作啊!
不过在本章中,我们主要还是在使用 bash 啦!
</fieldset><br> </div><br>
<a id="bash_why"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.1.2 为何要学文本接口的 shell?</h2>
<p><span class="text_import2">文本接口的 shell 是很不好学的,但是学了之后好处多多</span>!所以,
在这里鸟哥要先对您进行一些心理建设,先来了解一下为啥学习 shell 是有好处的,这样你才会有信心继续玩下去 ^_^
</p>
<ul class="toplist"><li>文本接口的 shell:大家都一样!</li></ul>
<p>鸟哥常常听到这个问题:『<span class="text_import2">我干嘛要学习 shell 呢?
不是已经有很多的工具可以提供我设置我的主机了?我为何要花这么多时间去学指令呢?不是以
X Window 按一按几个按钮就可以搞定了吗?</span>』唉~还是得一再地强调,
X Window 还有 Web 接口的设置工具例如 Webmin (<a href="0320bash.html#ps1">注1</a>) 是真的好用的家伙,
他真的可以帮助我们很简易的设置好我们的主机,甚至是一些很高端的设置都可以帮我们搞定。</p>
<p>但是鸟哥在前面的章节里面也已经提到过相当多次了, X Window 与 web 接口的工具,他的接口虽然亲善,功能虽然强大,
但毕竟他是将所有利用到的软件都集成在一起的一组应用程序而已,
并非是一个完整的套件,所以某些时候当你升级或者是使用其他套件管理模块 (例如 tarball 而非 rpm 文件等等)
时,就会造成设置的困扰了。甚至不同的 distribution 所设计的 X window 接口也都不相同,这样也造成学习方面的困扰。</p>
<p>文本接口的 shell 就不同了!几乎各家 distributions 使用的 bash 都是一样的!如此一来,
你就能够轻轻松松的转换不同的 distributions ,就像武侠小说里面提到的『一法通、万法通!』</p>
<ul class="toplist"><li>远程管理:文本接口就是比较快!</li></ul>
<p>此外,Linux 的管理常常需要透过远程连接,而连接时<span class="text_import2">文本接口的传输速度一定比较快,
而且,较不容易出现断线或者是信息外流的问题</span>,因此,shell 真的是得学习的一项工具。而且,他可以让您更深入
Linux ,更了解他,而不是只会按一按鼠标而已!所谓『天助自助者!』多摸一点文本模式的东西,会让你与
Linux 更亲近呢!</p>
<ul class="toplist"><li>Linux 的任督二脉: shell 是也!</li></ul>
<p>有些朋友也很可爱,常会说:『<span class="text_import2">我学这么多干什么?
又不常用,也用不到</span>!』嘿嘿!有没有听过『书到用时方恨少?』
当你的主机一切安然无恙的时候,您当然会觉得好像学这么多的东西一点帮助也没有呀!
万一,某一天真的不幸给他中标了,您该如何是好?是直接重新安装?
还是先追踪入侵来源后进行漏洞的修补?或者是干脆就关站好了?这当然涉及很多的考量,
但就以鸟哥的观点来看,多学一点总是好的,尤其我们可以有备而无患嘛!甚至学的不精也没有关系,了解概念也就
OK 啦!毕竟没有人要您一定要背这么多的内容啦!了解概念就很了不起了!</p>
<p>此外,<span class="text_import2">如果你真的有心想要将您的主机管理的好,那么良好的
shell 程序编写是一定需要的啦</span>!就鸟哥自己来说,鸟哥管理的主机虽然还不算多,
只有区区不到十部,但是如果每部主机都要花上几十分钟来查阅他的注册表信息以及相关的消息,
那么鸟哥可能会疯掉!基本上,也太没有效率了!这个时候,如果能够借由 shell 提供的数据流重导向以及管线命令,呵呵!
那么鸟哥分析登录信息只要花费不到十分钟就可以看完所有的主机之重要信息了!相当的好用呢!</p>
<p>由于学习 shell 的好处真的是多多啦!所以,如果你是个系统管理员,或者有心想要管理系统的话,那么
shell 与 shell scripts 这个东西真的有必要看一看!因为他就像『打通任督二脉,任何武功都能随你应用』的说!</p>
<br></div><br>
<a id="bash_shells"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.1.3 系统的合法 shell 与 /etc/shells 功能</h2>
<p>知道什么是 Shell 之后,那么我们来了解一下 Linux 使用的是哪一个 shell 呢?什么!哪一个?难道说 shell 不就是『一个 shell 吗?』哈哈!那可不!由于早年的
Unix 年代,发展者众,所以由于 shell 依据发展者的不同就有许多的版本,例如常听到的
Bourne SHell (sh) 、在 Sun 里头缺省的 C SHell、 商业上常用的 K SHell、,
还有 TCSH 等等,每一种 Shell 都各有其特点。至于 Linux 使用的这一种版本就称为『
<span class="text_import2">Bourne Again SHell (简称 bash)</span> 』,这个 Shell 是
Bourne Shell 的增强版本,也是基准于 GNU 的架构下发展出来的呦!</p>
<p>在介绍 shell 的优点之前,先来说一说 shell 的简单历史吧(<a href="0320bash.html#ps2">注2</a>):第一个流行的
shell 是由 Steven Bourne 发展出来的,为了纪念他所以就称为 Bourne shell
,或直接简称为 sh !而后来另一个广为流传的 shell 是由柏克莱大学的 Bill
Joy 设计依附于 BSD 版的 Unix 系统中的 shell ,这个 shell 的语法有点类似
C 语言,所以才得名为 C shell ,简称为 csh !由于在学术界 Sun
主机势力相当的庞大,而 Sun 主要是 BSD 的分支之一,所以 C shell
也是另一个很重要而且流传很广的 shell 之一 。</p>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 由于 Linux 为 C 编程语言撰写的,很多程序员使用 C 来开发软件,因此 C shell 相对的就很热门了。
另外,还记得我们在<a href="0110whatislinux.html">第一章、Linux 是什么</a>提到的吧?
Sun 公司的创始人就是 Bill Joy,而 BSD 最早就是 Bill Joy 发展出来的啊。
</fieldset><br>
<p>那么目前我们的 Linux (以 CentOS 7.x 为例) 有多少我们可以使用的 shells 呢?
你可以检查一下 /etc/shells 这个文件,至少就有底下这几个可以用的 shells (鸟哥省略了重复的 shell 了!包括 /bin/sh 等于 /usr/bin/sh 啰!):</p>
<ul>
<li>/bin/sh (已经被 /bin/bash 所取代)</li>
<li>/bin/bash (就是 Linux 缺省的 shell)</li>
<li>/bin/tcsh (集成 C Shell ,提供更多的功能)</li>
<li>/bin/csh (已经被 /bin/tcsh 所取代)</li>
</ul>
<p>虽然各家 shell 的功能都差不多,但是在某些语法的下达方面则有所不同,因此建议你还是得要选择某一种 shell 来熟悉一下较佳。
Linux 缺省就是使用 bash ,所以最初你只要学会 bash 就非常了不起了! ^_^!
另外,咦!<span class="text_import2">为什么我们系统上合法的 shell 要写入 /etc/shells 这个文件啊?</span>
这是因为系统某些服务在运作过程中,会去检查用户能够使用的 shells ,而这些 shell
的查找就是借由 /etc/shells 这个文件啰!</p>
<p>举例来说,某些 FTP 网站会去检查用户的可用 shell ,而如果你不想要让这些用户使用 FTP
以外的主机资源时,可能会给予该用户一些怪怪的 shell,让用户无法以其他服务登录主机。
这个时候,你就得将那些怪怪的 shell 写到 /etc/shells 当中了。举例来说,我们的 CentOS 7.x
的 /etc/shells 里头就有个 /sbin/nologin 文件的存在,这个就是我们说的怪怪的 shell 啰~</p>
<p>那么,再想一想,<span class="text_import2">我这个用户什么时候可以取得 shell 来工作呢?还有,
我这个用户缺省会取得哪一个 shell 啊</span>?还记得我们在<a href="0160startlinux.html#start_cmd">第四章的在终端接口登录linux小节</a>当中提到的登录动作吧?
当我登录的时候,系统就会给我一个 shell 让我来工作了。
而这个登录取得的 shell 就记录在 /etc/passwd 这个文件内!这个文件的内容是啥?</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">cat /etc/passwd</span>
root:x:0:0:root:/root:<span class="term_write">/bin/bash</span>
bin:x:1:1:bin:/bin:<span class="term_write">/sbin/nologin</span>
daemon:x:2:2:daemon:/sbin:<span class="term_write">/sbin/nologin</span>
<span class="term_say">.....(底下省略).....</span>
</pre></td></tr></tbody></table>
<p>如上所示,在每一行的最后一个数据,就是你登录后可以取得的缺省的 shell 啦!那你也会看到, root 是
/bin/bash ,不过,系统帐号 bin 与 daemon 等等,就使用那个怪怪的 /sbin/nologin
啰~关于用户这部分的内容,我们留在<a href="0410accountmanager.html">第十三章的帐号管理</a>时提供更多的说明。</p>
<br></div><br>
<a id="bash_bash"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.1.4 Bash shell 的功能</h2>
<p>既然 /bin/bash 是 Linux 缺省的 shell ,那么总是得了解一下这个玩意儿吧!bash 是 GNU 计划中重要的工具软件之一,目前也是
Linux distributions 的标准 shell 。 bash 主要兼容于 sh ,并且依据一些用户需求而加强的
shell 版本。不论你使用的是那个 distribution ,你都难逃需要学习 bash 的宿命啦!那么这个
shell 有什么好处,干嘛 Linux 要使用他作为缺省的 shell 呢? bash 主要的优点有底下几个:</p>
<ul class="toplist"><li>命令编修能力 (history):</li></ul>
<p>bash 的功能里头,鸟哥个人认为相当棒的一个就是『他能记忆使用过的指令!』
这功能真的相当的棒!因为我只要在指令列按『上下键』就可以找到前/后一个输入的指令!而在很多
distribution 里头,缺省的指令记忆功能可以到达 1000 个!也就是说,你曾经下达过的指令几乎都被记录下来了。</p>
<p>这么多的指令记录在哪里呢?在你的家目录内的 <span class="text_import2">.bash_history</span> 啦!
不过,需要留意的是,<span class="text_import2">~/.bash_history 记录的是前一次登录以前所运行过的指令,
而至于这一次登录所运行的指令都被暂存在内存中,当你成功的注销系统后,该指令记忆才会记录到 .bash_history 当中</span>!</p>
<p>这有什么优点呢?最大的好处就是可以『<span class="text_import2">查找曾经做过的举动</span>!』
如此可以知道你的运行步骤,那么就可以追踪你曾下达过的指令,以作为调试的重要流程!
但如此一来也有个烦恼,就是如果被骇客入侵了,那么他只要翻你曾经运行过的指令,
刚好你的指令又跟系统有关 (例如直接输入 MySQL 的密码在指令列上面),那你的服务器可就伤脑筋了!
到底记录指令的数目越多还是越少越好?这部份是见仁见智啦,没有一定的答案的。</p>
<a id="tab"></a>
<ul class="toplist"><li>命令与文件补全功能: ([tab] 按键的好处)</li></ul>
<p>还记得我们在<a href="0160startlinux.html#cmd_hkey">第四章内的重要的几个热键小节</a>当中提到的
[tab] 这个按键吗?这个按键的功能就是在 bash 里头才有的啦!常常在 bash 环境中使用 [tab]
是个很棒的习惯喔!因为至少可以让你 <span class="text_import2">1)少打很多字; 2)确定输入的数据是正确的!</span>
使用 [tab] 按键的时机依据 [tab] 接在指令后或参数后而有所不同。我们再复习一次:</p>
<ul class="text_import2">
<li>[Tab] 接在一串指令的第一个字的后面,则为命令补全;</li>
<li>[Tab] 接在一串指令的第二个字以后时,则为『文件补齐』!</li>
<li>若安装 bash-completion 软件,则在某些指令后面使用 [tab] 按键时,可以进行『选项/参数的补齐』功能!</li>
</ul>
<p>所以说,如果我想要知道我的环境当中所有以 c 为开头的指令呢?就按下『 c[tab][tab] 』就好啦! ^_^!
是的!真的是很方便的功能,所以,<span class="text_import2">有事没事,在
bash shell 底下,多按几次 [tab] 是一个不错的习惯啦</span>!</p>
<ul class="toplist"><li>命令别名设置功能: (alias)</li></ul>
<p>假如我需要知道这个目录底下的所有文件 (包含隐藏档) 及所有的文件属性,那么我就必须要下达『
ls -al 』这样的指令串,唉!真麻烦,有没有更快的取代方式?呵呵!就使用命令别名呀!例如鸟哥最喜欢直接以
lm 这个自订的命令来取代上面的命令,也就是说, <span class="text_import2">lm 会等于 ls -al</span>
这样的一个功能,嘿!那么要如何作呢?就使用 alias 即可!你可以在指令列输入 alias
就可以知道目前的命令别名有哪些了!也可以直接下达命令来设置别名呦:</p>
<ul><li class="text_import2" style="font-family:'细明体'">alias lm='ls -al'</li></ul>
<ul class="toplist"><li>工作控制、前景背景控制: (job control, foreground, background)</li></ul>
<p>这部分我们在<a href="0440processcontrol.html">第十六章 Linux 进程控制</a>中再提及!
使用前、背景的控制可以让工作进行的更为顺利!至于工作控制(jobs)的用途则更广,
可以让我们随时将工作丢到背景中运行!而不怕不小心使用了
[Ctrl] + c 来停掉该进程!真是好样的!此外,也可以在单一登录的环境中,达到多任务的目的呢!</p>
<ul class="toplist"><li>程序化脚本: (shell scripts)</li></ul>
<p>在 DOS 年代还记得将一堆指令写在一起的所谓的『批次档』吧?在 Linux 底下的
shell scripts 则发挥更为强大的功能,可以将你平时管理系统常需要下达的连续指令写成一个文件,
该文件并且可以透过对谈交互式的方式来进行主机的侦测工作!也可以借由
shell 提供的环境变量及相关指令来进行设计,哇!整个设计下来几乎就是一个小型的编程语言了!该
scripts 的功能真的是超乎鸟哥的想像之外!以前在 DOS 底下需要编程语言才能写的东西,在
Linux 底下使用简单的 shell scripts 就可以帮你达成了!真的厉害!这部分我们在<a href="0340bashshell-scripts.html">第十二章</a>再来谈!</p>
<ul class="toplist"><li>通配符: (Wildcard)</li></ul>
<p>除了完整的字符串之外, bash 还支持许多的通配符来帮助用户查找与指令下达。
举例来说,想要知道 /usr/bin 底下有多少以 X 为开头的文件吗?使用:『
ls -l /usr/bin/X* 』就能够知道啰~此外,还有其他可供利用的通配符,
这些都能够加快用户的操作呢!</p>
<p>总之,bash 这么好!不学吗?怎么可能!来学吧! ^_^</p>
<br></div><br>
<a id="bash_type"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.1.5 查找指令是否为 Bash shell 的内置命令: type</h2>
<p>我们在<a href="0160startlinux.html">第四章</a>提到关于
<a href="0160startlinux.html#manual_man">Linux 的在线说明文档</a>部分,也就是
man page 的内容,那么 bash 有没有什么说明文档啊?开玩笑~
这么棒的东西怎么可能没有说明文档!请你在 shell 的环境下,直接输入 man bash 瞧一瞧,
嘿嘿!不是盖的吧!让你看个几天几夜也无法看完的 bash 说明文档,可是很详尽的数据啊! ^_^</p>
<p>不过,在这个 bash 的 man page 当中,不知道你是否有察觉到,咦!
怎么这个说明文档里面有其他的文件说明啊?举例来说,那个 cd 指令的说明就在这个 man page 内?
然后我直接输入 man cd 时,怎么出现的画面中,最上方竟然出现一堆指令的介绍?这是怎么回事?
为了方便 shell 的操作,其实 bash 已经『内置』了很多指令了,例如上面提到的 cd ,
还有例如 umask 等等的指令,都是内置在 bash 当中的呢!</p>
<p>那我怎么知道这个指令是来自于外部指令(指的是其他非 bash 所提供的指令) 或是内置在 bash 当中的呢?
嘿嘿!利用 type 这个指令来观察即可!举例来说:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">type [-tpa] name</span>
<span class="term_say">选项与参数:
:不加任何选项与参数时,type 会显示出 name 是外部指令还是 bash 内置指令
-t :当加入 -t 参数时,type 会将 name 以底下这些字眼显示出他的意义:
file :表示为外部指令;
alias :表示该指令为命令别名所设置的名称;
builtin :表示该指令为 bash 内置的指令功能;
-p :如果后面接的 name 为外部指令时,才会显示完整文件名;
-a :会由 PATH 变量定义的路径中,将所有含 name 的指令都列出来,包含 alias</span>
<span class="term_hd">范例一:查找一下 ls 这个指令是否为 bash 内置?</span>
[dmtsai@study ~]$ <span class="term_command">type ls</span>
ls is aliased to `ls --color=auto' <span class="term_note"><==未加任何参数,列出 ls 的最主要使用情况</span>
[dmtsai@study ~]$ <span class="term_command">type -t ls</span>
alias <span class="term_note"><==仅列出 ls 运行时的依据</span>
[dmtsai@study ~]$ <span class="term_command">type -a ls</span>
ls is aliased to `ls --color=auto' <span class="term_note"><==最先使用 aliase</span>
ls is /usr/bin/ls <span class="term_note"><==还有找到外部指令在 /bin/ls</span>
<span class="term_hd">范例二:那么 cd 呢?</span>
[dmtsai@study ~]$ <span class="term_command">type cd</span>
cd is a shell builtin <span class="term_note"><==看到了吗? cd 是 shell 内置指令</span>
</pre></td></tr></tbody></table>
<p>透过 type 这个指令我们可以知道每个指令是否为 bash 的内置指令。
此外,由于利用 type 搜索后面的名称时,如果后面接的名称并不能以运行档的状态被找到,
那么该名称是不会被显示出来的。也就是说, type 主要在找出『运行档』而不是一般文件文件名喔!
呵呵!所以,<span class="text_import2">这个 type 也可以用来作为类似 <a href="0220filemanager.html#which">which</a>
指令的用途啦!</span>找指令用的!</p>
<br></div><br>
<a id="bash_command"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.1.6 指令的下达与快速编辑按钮</h2>
<p>我们在<a href="0160startlinux.html#cmd_cmd">第四章的开始下达指令小节</a>已经提到过在
shell 环境下的指令下达方法,如果你忘记了请回到第四章再去回忆一下!这里不重复说明了。
鸟哥这里仅就反斜线 (\) 来说明一下指令下达的方式啰!</p>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例:如果指令串太长的话,如何使用两行来输出?</span>
[dmtsai@study ~]$ <span class="term_command">cp /var/spool/mail/root /etc/crontab \</span>
> <span class="term_command">/etc/fstab /root</span>
</pre></td></tr></tbody></table>
<p>上面这个指令用途是将三个文件复制到 /root 这个目录下而已。不过,因为指令太长,
于是鸟哥就利用『 \[Enter] 』来将 [Enter] 这个按键『跳脱!』开来,让
[Enter] 按键不再具有『开始运行』的功能!好让指令可以继续在下一行输入。
<span class="text_import2">需要特别留意, [Enter] 按键是紧接着反斜线 (\) 的,两者中间没有其他字符。
因为 \ 仅跳脱『紧接着的下一个字符』而已</span>!所以,万一我写成:
『<span class="text_import2" style="font-family:'细明体'"> \ [Enter]</span> 』,亦即
[Enter] 与反斜线中间有一个空格时,则 \ 跳脱的是『空白键』而不是 [Enter] 按键!这个地方请再仔细的看一遍!很重要!</p>
<p>如果顺利跳脱 [Enter] 后,下一行最前面就会主动出现 > 的符号,
你可以继续输入指令啰!也就是说,那个 > 是系统自动出现的,你不需要输入。</p>
<p>另外,当你所需要下达的指令特别长,或者是你输入了一串错误的指令时,你想要快速的将这串指令整个删除掉,一般来说,我们都是按下删除键的。
有没有其他的快速组合键可以协助呢?是有的!常见的有底下这些:</p>
<table class="news" style="width: 90%">
<tbody><tr class="theader"><td>组合键</td><td>功能与示范</td></tr>
<tr><td>[ctrl]+u/[ctrl]+k</td><td>分别是从光标处向前删除指令串 ([ctrl]+u) 及向后删除指令串 ([ctrl]+k)。</td></tr>
<tr><td>[ctrl]+a/[ctrl]+e</td><td>分别是让光标移动到整个指令串的最前面 ([ctrl]+a) 或最后面 ([ctrl]+e)。</td></tr>
</tbody></table>
<p>总之,当我们顺利的在终端机 (tty) 上面登录后, Linux 就会依据 /etc/passwd
文件的设置给我们一个 shell (缺省是 bash),然后我们就可以依据上面的指令下达方式来操作 shell,
之后,我们就可以透过 man 这个在线查找来查找指令的使用方式与参数说明,
很不错吧!那么我们就赶紧更进一步来操作 bash 这个好玩的东西啰!</p>
<br></div>
</div>
<a id="variable"></a>
<div class="block1">
<h2>10.2 Shell 的变量功能</h2>
<p>变量是 bash 环境中非常重要的一个玩意儿,我们知道 Linux 是多人多任务的环境,每个人登录系统都能取得一个 bash shell,
每个人都能够使用 bash 下达 mail 这个指令来收受『自己』的邮件等等。问题是, bash 是如何得知你的邮件信箱是哪个文件?
这就需要『变量』的帮助啦!所以,你说变量重不重要呢?底下我们将介绍重要的环境变量、变量的取用与设置等数据,
呼呼!动动脑时间又来到啰!^_^</p>
<a id="variable_var"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.2.1 什么是变量?</h2>
<p>那么,什么是『变量』呢?简单的说,就是让某一个特定字符串代表不固定的内容就是了。举个大家在国中都会学到的数学例子,
那就是:『 y = ax + b 』这东西,<span class="text_import2">在等号左边的(y)就是变量,在等号右边的(ax+b)就是变量内容。
要注意的是,左边是未知数,右边是已知数喔!</span>
讲的更简单一点,我们可以『<span class="text_import2">用一个简单的 "字眼"
来取代另一个比较复杂或者是容易变动的数据</span>』。这有什么好处啊?最大的好处就是『方便!』。</p>
<ul class="toplist"><li>变量的可变性与方便性</li></ul>
<a id="mail"></a>
<p>举例来说,我们每个帐号的邮件信箱缺省是以 MAIL 这个变量来进行访问的,
当 dmtsai 这个用户登录时,他便会取得 MAIL 这个变量,而这个变量的内容其实就是 /var/spool/mail/dmtsai,
那如果 vbird 登录呢?他取得的 MAIL 这个变量的内容其实就是 /var/spool/mail/vbird 。
而我们使用信件读取指令 mail 来读取自己的邮件信箱时,嘿嘿,这支程序可以直接读取 MAIL 这个变量的内容,
就能够自动的分辨出属于自己的信箱信件啰!这样一来,设计程序的设计师就真的很方便的啦!</p>
<a id="fig10.2.1"></a>
<div style="text-align:center; margin: 0 auto 0 auto; "><img src="./vbird_files/var_01.gif" alt="程序、变量与不同用户的关系" title="程序、变量与不同用户的关系" style="border: 1px solid black; padding: 10px "></div>
<div style="text-align: center;">图10.2.1、程序、变量与不同用户的关系</div>
<p>如上图所示,由于系统已经帮我们规划好 MAIL 这个变量,所以用户只要知道 mail 这个指令如何使用即可,
mail 会主动的取用 MAIL 这个变量,就能够如上图所示的取得自己的邮件信箱了!(注意大小写,小写的 mail 是指令,
大写的 MAIL 则是变量名称喔!)</p>
<p>那么使用变量真的比较好吗?这是当然的!想像一个例子,如果 mail 这个指令将 root 收信的邮件信箱 (mailbox) 文件名为
/var/spool/mail/root 直接写入代码中。那么当 dmtsai 要使用 mail 时,将会取得 /var/spool/mail/root 这个文件的内容!
不合理吧!所以你就需要帮 dmtsai 也设计一个 mail 的程序,将 /var/spool/mail/dmtsai 写死到 mail 的代码当中!
天呐!那系统要有多少个 mail 指令啊?反过来说,使用变量就变的很简单了!因为你不需要更动到代码啊!
只要将 MAIL 这个变量带入不同的内容即可让所有用户透过 mail 取得自己的信件!当然简单多了!</p>
<ul class="toplist"><li>影响 bash 环境操作的变量</li></ul>
<p>某些特定变量会影响到 bash 的环境喔!举例来说,我们前面已经提到过很多次的那个 PATH 变量!
你能不能在任何目录下运行某个指令,与 PATH 这个变量有很大的关系。例如你下达 ls 这个指令时,系统就是透过 PATH
这个变量里面的内容所记录的路径顺序来搜索指令的呢!如果在搜索完 PATH 变量内的路径还找不到 ls 这个指令时,
就会在屏幕上显示『 command not found 』的错误消息了。</p>
<p>如果说的学理一点,那么由于在 Linux System 下面,所有的线程都是需要一个运行码,
而就如同上面提到的,你『<span class="text_import2">真正以
shell 来跟 Linux 沟通,是在正确的登录 Linux 之后!</span>』这个时候你就有一个
bash 的运行进程,也才可以真正的经由 bash 来跟系统沟通啰!而在进入 shell
之前,也正如同上面提到的,由于系统需要一些变量来提供他数据的访问 (或者是一些环境的设置参数值,
例如是否要显示彩色等等的) ,所以就有一些所谓的『<span class="text_import2">环境变量</span>』
需要来读入系统中了!这些环境变量例如 PATH、HOME、MAIL、SHELL 等等,都是很重要的,
为了区别与自订变量的不同,环境变量通常以大写字符来表示呢!</p>
<ul class="toplist"><li>脚本编程 (shell script) 的好帮手</li></ul>
<p>这些还都只是系统缺省的变量的目的,如果是个人的设置方面的应用呢:例如你要写一个大型的
script 时,有些数据因为可能由于用户习惯的不同而有差异,比如说路径好了,由于该路径在
script 被使用在相当多的地方,如果下次换了一部主机,都要修改 script 里面的所有路径,那么我一定会疯掉!
这个时候如果使用变量,而将该变量的定义写在最前面,后面相关的路径名称都以变量来取代,
嘿嘿!那么你只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程序员都会善用变量的定义!</p>
<a id="fig10.2.2"></a>
<div style="text-align:center; margin: 0 auto 0 auto; "><img src="./vbird_files/var_02.gif" alt="变量应用于 shell script 的示意图" title="变量应用于 shell script 的示意图" style="border: 1px solid black; padding: 10px "></div>
<div style="text-align: center;">图10.2.2、变量应用于 shell script 的示意图</div>
<p>最后我们就简单的对『<span class="text_import2">什么是变量</span>』作个简单定义好了:
『<span class="text_import2">变量就是以一组文本或符号等,来取代一些设置或者是一串保留的数据!</span>』,
例如:我设置了『myname』就是『VBird』,所以当你读取
myname 这个变量的时候,系统自然就会知道!哈!那就是 VBird 啦!
那么如何『<span class="text_import2">显示变量</span>』呢?这就需要使用到 echo 这个指令啦!</p>
<br></div><br>
<a id="variable_echo"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.2.2 变量的取用与设置:echo, 变量设置规则, unset</h2>
<p>说的口沫横飞的,也不知道『变量』与『变量代表的内容』有啥关系?
那我们就将『变量』的『内容』拿出来给您瞧瞧好了。你可以利用 echo 这个指令来取用变量,
但是,变量在被取用时,前面必须要加上钱字号『 $ 』才行,举例来说,要知道 PATH 的内容,该如何是好?</p>
<a id="echo"></a>
<ul class="toplist"><li>变量的取用: echo</li></ul>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">echo $variable</span>
[dmtsai@study ~]$ <span class="term_command">echo $PATH</span>
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
[dmtsai@study ~]$ <span class="term_command">echo ${PATH}</span> <span class="term_note"># 近年来,鸟哥比较偏向使用这种格式喔!</span>
</pre></td></tr></tbody></table>
<p>变量的取用就如同上面的范例,利用 echo 就能够读出,只是需要在变量名称前面加上 $ ,
或者是以 ${变量} 的方式来取用都可以!当然啦,那个 echo 的功能可是很多的,
我们这里单纯是拿 echo 来读出变量的内容而已,更多的 echo 使用,请自行给他 man echo 吧! ^_^</p>
<table class="exam"><tbody><tr><td>
例题:<div>
请在屏幕上面显示出您的环境变量 HOME 与 MAIL:
</div>
答:<div>
<span class="text_import2" style="font-family:'细明体'">echo $HOME 或者是 echo ${HOME}<br>echo $MAIL 或者是 echo ${MAIL}</span>
</div>
</td></tr></tbody></table>
<p>现在我们知道了变量与变量内容之间的相关性了,好了,那么我要如何『设置』或者是『修改』
某个变量的内容啊?很简单啦!用『等号(=)』连接变量与他的内容就好啦!举例来说:
我要将 myname 这个变量名称的内容设置为 VBird ,那么:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">echo ${myname}</span>
<span class="term_note"><==这里并没有任何数据~因为这个变量尚未被设置!是空的!</span>
[dmtsai@study ~]$ <span class="term_command">myname=VBird</span>
[dmtsai@study ~]$ <span class="term_command">echo ${myname}</span>
VBird <span class="term_note"><==出现了!因为这个变量已经被设置了!</span>
</pre></td></tr></tbody></table>
<p>瞧!如此一来,这个变量名称 myname 的内容就带有 VBird 这个数据啰~
而由上面的例子当中,我们也可以知道:
<span class="text_import2">在 bash 当中,当一个变量名称尚未被设置时,缺省的内容是『空』的</span>。
另外,变量在设置时,还是需要符合某些规定的,否则会设置失败喔!这些规则如下所示啊!</p>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 要请各位读者注意喔,每一种 shell 的语法都不相同~在变量的使用上,bash 在你没有设置的变量中强迫去 echo 时,它会显示出空的值。
在其他某些 shell 中,随便去 echo 一个不存在的变量,它是会出现错误消息的喔!要注意!要注意!
</fieldset><br>
<a id="variable_rule"></a>
<ul class="toplist"><li>变量的设置规则</li></ul>
<ol style="font-family:'细明体'">
<li><span class="text_import2">变量与变量内容以一个等号『=』来链接</span>,如下所示:
<br>『myname=VBird』<br><br></li>
<li><span class="text_import2">等号两边不能直接接空白字符</span>,如下所示为错误:
<br>『myname = VBird』或『myname=VBird Tsai』<br><br></li>
<li>变量名称只能是英文本母与数字,但是<span class="text_import2">开头字符不能是数字</span>,如下为错误:
<br>『2myname=VBird』<br><br></li>
<li>变量内容若有空白字符可使用双引号『"』或单引号『'』将变量内容结合起来,但
<ul style="padding-left: 15px">
<li><span class="text_import2">双引号内的特殊字符如 $ 等,可以保有原本的特性</span>,如下所示:<br>
『var="lang is $LANG"』则『echo $var』可得『lang is zh_TW.UTF-8』</li>
<li><span class="text_import2">单引号内的特殊字符则仅为一般字符 (纯文本)</span>,如下所示:<br>
『var='lang is $LANG'』则『echo $var』可得『lang is $LANG』</li>
</ul><br></li>
<li>可用<span class="text_import2">跳脱字符『 \ 』</span>将特殊符号(如 [Enter], $, \, 空白字符,
'等)变成一般字符,如:<br>
『myname=VBird\ Tsai』<br><br></li>
<li>在一串指令的运行中,还需要借由其他额外的指令所提供的信息时,可以<span class="text_import2">使用反单引号『`指令`』或
『$(指令)』</span>。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号!
例如想要取得核心版本的设置:<br>『version=$(uname -r)』再『echo
$version』可得『3.10.0-229.el7.x86_64』<br><br></li>
<li>若该变量为扩增变量内容时,则可用 "$变量名称" 或 ${变量} 累加内容,如下所示:<br>
『PATH="$PATH":/home/bin』或『PATH=${PATH}:/home/bin』<br><br></li>
<li>若该变量需要在其他子进程运行,则<span class="text_import2">需要以 export 来使变量变成环境变量</span>:<br>
『export PATH』<br><br></li>
<li>通常大写字符为系统缺省变量,自行设置变量可以使用小写字符,方便判断 (纯粹依照用户兴趣与嗜好) ;<br><br></li>
<li><a id="unset"></a><span class="text_import2">取消变量的方法为使用 unset</span> :『unset
变量名称』例如取消 myname 的设置:<br>
『unset myname』</li>
</ol>
<p>底下让鸟哥举几个例子来让你试看看,就知道怎么设置好你的变量啰!</p>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例一:设置一变量 name ,且内容为 VBird</span>
[dmtsai@study ~]$ <span class="term_command">12name=VBird</span>
bash: 12name=VBird: command not found... <span class="term_note"><==屏幕会显示错误!因为不能以数字开头!</span>
[dmtsai@study ~]$ <span class="term_command">name = VBird</span> <span class="term_note"><==还是错误!因为有空白!</span>
[dmtsai@study ~]$ <span class="term_command">name=VBird</span> <span class="term_note"><==OK 的啦!</span>
<span class="term_hd">范例二:承上题,若变量内容为 VBird's name 呢,就是变量内容含有特殊符号时:</span>
[dmtsai@study ~]$ <span class="term_command">name=VBird's name</span>
<span class="term_say"># <u>单引号与双引号必须要成对</u>,在上面的设置中仅有一个单引号,因此当你按下 enter 后,
# 你还可以继续输入变量内容。这与我们所需要的功能不同,失败啦!
# 记得,失败后要复原请按下 [ctrl]-c 结束!</span>
[dmtsai@study ~]$ <span class="term_command">name="VBird's name"</span> <span class="term_note"><==OK 的啦!</span>
<span class="term_say"># 指令是由左边向右找→,先遇到的引号先有用,因此如上所示, 单引号变成一般字符!</span>
[dmtsai@study ~]$ <span class="term_command">name='VBird's name'</span> <span class="term_note"><==失败的啦!</span>
<span class="term_say"># 因为前两个单引号已成对,后面就多了一个不成对的单引号了!因此也就失败了!</span>
[dmtsai@study ~]$ <span class="term_command">name=VBird\'s\ name</span> <span class="term_note"><==OK 的啦!</span>
<span class="term_say"># 利用反斜线 (\) 跳脱特殊字符,例如单引号与空白键,这也是 OK 的啦!</span>
<span class="term_hd">范例三:我要在 PATH 这个变量当中『累加』:/home/dmtsai/bin 这个目录</span>
[dmtsai@study ~]$ <span class="term_command">PATH=$PATH:/home/dmtsai/bin</span>
[dmtsai@study ~]$ <span class="term_command">PATH="$PATH":/home/dmtsai/bin</span>
[dmtsai@study ~]$ <span class="term_command">PATH=${PATH}:/home/dmtsai/bin</span>
<span class="term_say"># 上面这三种格式在 PATH 里头的设置都是 OK 的!但是底下的例子就不见得啰!</span>
<span class="term_hd">范例四:承范例三,我要将 name 的内容多出 "yes" 呢?</span>
[dmtsai@study ~]$ <span class="term_command">name=$nameyes</span>
<span class="term_say"># 知道了吧?如果没有双引号,那么变量成了啥?name 的内容是 $nameyes 这个变量!
# 呵呵!我们可没有设置过 nameyes 这个变量呐!所以,应该是底下这样才对!</span>
[dmtsai@study ~]$ <span class="term_command">name="$name"yes</span>
[dmtsai@study ~]$ <span class="term_command">name=${name}yes</span> <span class="term_note"><==以此例较佳!</span>
<span class="term_hd">范例五:如何让我刚刚设置的 name=VBird 可以用在下个 shell 的进程?</span>
[dmtsai@study ~]$ <span class="term_command">name=VBird</span>
[dmtsai@study ~]$ <span class="term_command">bash </span> <span class="term_note"><==进入到所谓的子进程</span>
[dmtsai@study ~]$ <span class="term_command">echo $name</span> <span class="term_note"><==子进程:再次的 echo 一下;</span>
<span class="term_note"><==嘿嘿!并没有刚刚设置的内容喔!</span>
[dmtsai@study ~]$ <span class="term_command">exit </span> <span class="term_note"><==子进程:离开这个子进程</span>
[dmtsai@study ~]$ <span class="term_command">export name</span>
[dmtsai@study ~]$ <span class="term_command">bash </span> <span class="term_note"><==进入到所谓的子进程</span>
[dmtsai@study ~]$ <span class="term_command">echo $name</span> <span class="term_note"><==子进程:在此运行!</span>
VBird <span class="term_note"><==看吧!出现设置值了!</span>
[dmtsai@study ~]$ <span class="term_command">exit </span> <span class="term_note"><==子进程:离开这个子进程</span>
</pre></td></tr></tbody></table>
<p>什么是『子进程』呢?就是说,在我目前这个 shell 的情况下,去启用另一个新的 shell ,新的那个 shell
就是子进程啦!在一般的状态下,父进程的自订变量是无法在子进程内使用的。但是透过 export
将变量变成环境变量后,就能够在子进程底下应用了!很不赖吧!至于进程的相关概念,
我们会在<a href="0440processcontrol.html">第十六章进程管理</a>当中提到的喔!</p>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例六:如何进入到您目前核心的模块目录?</span>
[dmtsai@study ~]$ <span class="term_command">cd /lib/modules/`uname -r`/kernel</span>
[dmtsai@study ~]$ <span class="term_command">cd /lib/modules/$(uname -r)/kernel</span> <span class="term_note"># 以此例较佳!</span>
</pre></td></tr></tbody></table>
<p>每个 Linux 都能够拥有多个核心版本,且几乎 distribution 的核心版本都不相同。以 CentOS 7.1 (未更新前)
为例,他的缺省核心版本是 3.10.0-229.el7.x86_64 ,所以核心模块目录在 /lib/modules/3.10.0-229.el7.x86_64/kernel/ 内。
也由于每个 distributions 的这个值都不相同,但是我们却可以利用 uname -r
这个指令先取得版本信息。所以啰,就可以透过上面指令当中的内含指令 $(uname -r)
先取得版本输出到 cd ... 那个指令当中,就能够顺利的进入目前核心的驱动程序所放置的目录啰!很方便吧!</p>
<p>其实上面的指令可以说是作了两次动作,亦即是:</p>
<ol>
<li>先进行反单引号内的动作『uname -r』并得到核心版本为 3.10.0-229.el7.x86_64</li>
<li>将上述的结果带入原指令,故得指令为:『cd /lib/modules/3.10.0-229.el7.x86_64/kernel/』</li>
</ol>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 为什么鸟哥比较建议记忆 $( command ) 呢?还记得小时候学数学的加减乘除,我们都知道得要先乘除后加减。那如果硬要先加减再乘除呢?
当然就是加上括号 () 来处理即可啊!所以啰,这个指令的处理方式也差不多,只是括号左边得要加个钱字号就是了!
</fieldset><br>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例七:取消刚刚设置的 name 这个变量内容</span>
[dmtsai@study ~]$ <span class="term_command">unset name</span>
</pre></td></tr></tbody></table>
<p>根据上面的案例你可以试试看!就可以了解变量的设置啰!这个是很重要的呦!请勤加练习!
其中,较为重要的一些特殊符号的使用啰!例如单引号、双引号、跳脱字符、钱字号、反单引号等等,底下的例题想一想吧!</p>
<table class="exam" style="width: 90%"><tbody><tr><td>
例题:<div>
在变量的设置当中,单引号与双引号的用途有何不同?<br>
</div>
答:<div>
单引号与双引号的最大不同在于<span class="text_import2">双引号仍然可以保有变量的内容,但单引号内仅能是一般字符
,而不会有特殊符号。</span>我们以底下的例子做说明:假设您定义了一个变量, name=VBird ,现在想以
name 这个变量的内容定义出 myname 显示 VBird its me 这个内容,要如何订定呢?
<blockquote class="text_import2" style="font-family:'细明体'">
[dmtsai@study ~]$ name=VBird<br>
[dmtsai@study ~]$ echo $name<br>
VBird<br>
[dmtsai@study ~]$ myname="$name its me"<br>
[dmtsai@study ~]$ echo $myname<br>
VBird its me<br>
[dmtsai@study ~]$ myname='$name its me'<br>
[dmtsai@study ~]$ echo $myname<br>
$name its me</blockquote>
发现了吗?没错!使用了单引号的时候,那么 $name 将失去原有的变量内容,仅为一般字符的显示型态而已!这里必需要特别小心在意!
</div>
</td></tr></tbody></table><br>
<table class="exam" style="width:90%"><tbody><tr><td>
例题:<div>
在指令下达的过程中,反单引号( ` )这个符号代表的意义为何?
</div>
答:<div>
在一串指令中,在 ` 之内的指令将会被先运行,而其运行出来的结果将做为外部的输入信息!例如
uname -r 会显示出目前的核心版本,而我们的核心版本在 /lib/modules 里面,因此,你可以先运行
uname -r 找出核心版本,然后再以『 cd 目录』到该目录下,当然也可以运行如同上面范例六的运行内容啰。
<br><br>另外再举个例子,我们也知道, <a href="0220filemanager.html#locate">locate</a>
指令可以列出所有的相关文件文件名,但是,如果我想要知道各个文件的权限呢?举例来说,我想要知道每个 crontab 相关文件名的权限:
<blockquote style="font-family:'细明体'" class="text_import2">
[dmtsai@study ~]$ ls -ld `locate crontab`<br>
[dmtsai@study ~]$ ls -ld $(locate crontab)</blockquote>
如此一来,先以 locate 将文件名数据都列出来,再以 ls 指令来处理的意思啦!瞭了吗? ^_^
</div>
</td></tr></tbody></table><br>
<table class="exam" style="width:90%"><tbody><tr><td>
例题:<div>
若你有一个常去的工作目录名称为:『/cluster/server/work/taiwan_2015/003/』,如何进行该目录的简化?
</div>
答:<div>
在一般的情况下,如果你想要进入上述的目录得要『cd /cluster/server/work/taiwan_2015/003/』,
以鸟哥自己的案例来说,鸟哥跑数值模式常常会设置很长的目录名称(避免忘记),但如此一来变换目录就很麻烦。
此时,鸟哥习惯利用底下的方式来降低指令下达错误的问题:<blockquote style="font-family:'细明体'" class="text_import2">
[dmtsai@study ~]$ work="/cluster/server/work/taiwan_2015/003/"<br>
[dmtsai@study ~]$ cd $work</blockquote>
未来我想要使用其他目录作为我的模式工作目录时,只要变更 work 这个变量即可!而这个变量又可以在 <a href="0320bash.html#settings_bashrc">bash
的设置档</a>(~/.bashrc)中直接指定,那我每次登录只要运行『 cd $work 』就能够去到数值模式仿真的工作目录了!是否很方便呢? ^_^
</div>
</td></tr></tbody></table><br>
<br></div><br>
<a id="variable_environ"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.2.3 环境变量的功能</h2>
<p>环境变量可以帮我们达到很多功能~包括家目录的变换啊、提示字符的显示啊、运行档搜索的路径啊等等的,
还有很多很多啦!那么,既然环境变量有那么多的功能,问一下,目前我的 shell 环境中,
有多少缺省的环境变量啊?我们可以利用两个指令来查阅,分别是 env 与 export 呢!</p>
<a id="env"></a>
<ul class="toplist"><li>用 env 观察环境变量与常见环境变量说明</li></ul>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例一:列出目前的 shell 环境下的所有环境变量与其内容。</span>
[dmtsai@study ~]$ <span class="term_command">env</span>
HOSTNAME=study.centos.vbird <span class="term_note"><== 这部主机的主机名称</span>
TERM=xterm <span class="term_note"><== 这个终端机使用的环境是什么类型</span>
SHELL=/bin/bash <span class="term_note"><== 目前这个环境下,使用的 Shell 是哪一个程序?</span>
HISTSIZE=1000 <span class="term_note"><== 『记录指令的笔数』在 CentOS 缺省可记录 1000 笔</span>
OLDPWD=/home/dmtsai <span class="term_note"><== 上一个工作目录的所在</span>
LC_ALL=en_US.utf8 <span class="term_note"><== 由于语系的关系,鸟哥偷偷丢上来的一个设置</span>
USER=dmtsai <span class="term_note"><== 用户的名称啊!</span>
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:
or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:
*.tar=01... <span class="term_note"><== 一些颜色显示</span>
MAIL=/var/spool/mail/dmtsai <span class="term_note"><== 这个用户所取用的 mailbox 位置</span>
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
PWD=/home/dmtsai <span class="term_note"><== 目前用户所在的工作目录 (利用 pwd 取出!)</span>
LANG=zh_TW.UTF-8 <span class="term_note"><== 这个与语系有关,底下会再介绍!</span>
HOME=/home/dmtsai <span class="term_note"><== 这个用户的家目录啊!</span>
LOGNAME=dmtsai <span class="term_note"><== 登录者用来登录的帐号名称</span>
_=/usr/bin/env <span class="term_note"><== 上一次使用的指令的最后一个参数(或指令本身)</span>
</pre></td></tr></tbody></table>
<p>env 是 environment (环境) 的简写啊,上面的例子当中,是列出来所有的环境变量。当然,如果使用 export 也会是一样的内容~
只不过, export 还有其他额外的功能就是了,我们等一下再提这个 export 指令。
那么上面这些变量有些什么功用呢?<a id="variable_environ_im"></a>底下我们就一个一个来分析分析!</p>
<ul style="padding-left: 25px">
<li><span class="text_import1">HOME</span><br>代表用户的家目录。还记得我们可以使用 cd ~
去到自己的家目录吗?或者利用 cd 就可以直接回到用户家目录了。那就是取用这个变量啦~
有很多程序都可能会取用到这个变量的值!<br><br></li>
<li><span class="text_import1">SHELL</span><br>告知我们,目前这个环境使用的 SHELL 是哪支程序?
Linux 缺省使用 /bin/bash 的啦!<br><br></li>
<li><span class="text_import1">HISTSIZE</span><br>这个与『历史命令』有关,亦即是,
我们曾经下达过的指令可以被系统记录下来,而记录的『笔数』则是由这个值来设置的。<br><br></li>
<li><span class="text_import1">MAIL</span><br>当我们使用 mail 这个指令在收信时,系统会去读取的邮件信箱文件
(mailbox)。<br><br></li>
<li><span class="text_import1">PATH</span><br>就是运行档搜索的路径啦~目录与目录中间以冒号(:)分隔,
由于文件的搜索是依序由 PATH 的变量内的目录来查找,所以,目录的顺序也是重要的喔。<br><br></li>
<li><span class="text_import1">LANG</span><br>这个重要!就是语系数据啰~很多消息都会用到他,
举例来说,当我们在启动某些 perl 的编程语言文件时,他会主动的去分析语系数据文件,
如果发现有他无法解析的编码语系,可能会产生错误喔!一般来说,我们中文编码通常是 zh_TW.Big5 或者是
zh_TW.UTF-8,这两个编码偏偏不容易被解译出来,所以,有的时候,可能需要修订一下语系数据。
这部分我们会在下个小节做介绍的!<br><br></li>
<li><span class="text_import1">RANDOM</span><br>这个玩意儿就是『随机乱数』的变量啦!目前大多数的
distributions 都会有乱数产生器,那就是<span class="text_import2"> /dev/random</span> 这个文件。
我们可以透过这个乱数文件相关的变量 ($RANDOM) 来随机取得乱数值喔。在 BASH 的环境下,这个 RANDOM
变量的内容,介于 0~32767 之间,所以,你只要 echo $RANDOM 时,系统就会主动的随机取出一个介于
0~32767 的数值。万一我想要使用 0~9 之间的数值呢?呵呵~利用 declare 声明数值类型,
然后这样做就可以了:<br>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">declare -i number=$RANDOM*10/32768 ; echo $number</span>
8 <span class="term_note"><== 此时会随机取出 0~9 之间的数值喔!</span>
</pre></td></tr></tbody></table></li>
</ul>
<p>大致上是有这些环境变量啦~里面有些比较重要的参数,在底下我们都会另外进行一些说明的~</p>
<a id="set"></a>
<ul class="toplist"><li>用 set 观察所有变量 (含环境变量与自订变量)</li></ul>
<p>bash 可不只有环境变量喔,还有一些与 bash 操作接口有关的变量,以及用户自己定义的变量存在的。
那么这些变量如何观察呢?这个时候就得要使用 set 这个指令了。 set 除了环境变量之外,
还会将其他在 bash 内的变量通通显示出来哩!信息很多,底下鸟哥仅列出几个重要的内容:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">set</span>
BASH=/bin/bash <span class="term_note"><== bash 的主程序放置路径</span>
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(1)-release' <span class="term_note"><== 这两行是 bash 的版本啊!</span>
COLUMNS=90 <span class="term_note"><== 在目前的终端机环境下,使用的字段有几个字符长度</span>
<span class="term_write">HISTFILE=/home/dmtsai/.bash_history</span> <span class="term_note"><== 历史命令记录的放置文件,隐藏档</span>
HISTFILESIZE=1000 <span class="term_note"><== 存起来(与上个变量有关)的文件之指令的最大纪录笔数。</span>
HISTSIZE=1000 <span class="term_note"><== 目前环境下,内存中记录的历史命令最大笔数。</span>
IFS=$' \t\n' <span class="term_note"><== 缺省的分隔符号</span>
LINES=20 <span class="term_note"><== 目前的终端机下的最大行数</span>
MACHTYPE=x86_64-redhat-linux-gnu <span class="term_note"><== 安装的机器类型</span>
OSTYPE=linux-gnu <span class="term_note"><== 操作系统的类型!</span>
<span class="term_write">PS1='[\u@\h \W]\$ '</span> <span class="term_note"><== PS1 就厉害了。这个是命令提示字符,也就是我们常见的
[root@www ~]# 或 [dmtsai ~]$ 的设置值啦!可以更动的!</span>
<span class="term_write">PS2='> '</span> <span class="term_note"><== 如果你使用跳脱符号 (\) 第二行以后的提示字符也</span>
<span class="term_write">$</span> <span class="term_note"><== 目前这个 shell 所使用的 PID</span>
<span class="term_write">?</span> <span class="term_note"><== 刚刚运行完指令的回传值。</span>
...
<span class="term_say"># 有许多可以使用的函数库功能被鸟哥取消啰!请自行查阅!</span>
</pre></td></tr></tbody></table>
<p>一般来说,不论是否为环境变量,只要跟我们目前这个 shell 的操作接口有关的变量,
通常都会被设置为大写字符,也就是说,『<span class="text_import2">基本上,在 Linux
缺省的情况中,使用{大写的字母}来设置的变量一般为系统内定需要的变量</span>』。
OK!OK!那么上头那些变量当中,有哪些是比较重要的?大概有这几个吧!</p>
<div class="illus">
<ul><li>PS1:(提示字符的设置)</li></ul>
<p>这是 PS1 (数字的 1 不是英文本母),这个东西就是我们的『<span class="text_import2">命令提示字符</span>』喔!
当我们每次按下 [Enter] 按键去运行某个指令后,最后要再次出现提示字符时,
就会主动去读取这个变量值了。上头 PS1 内显示的是一些特殊符号,这些特殊符号可以显示不同的信息,
每个 distributions 的 bash 缺省的 PS1 变量内容可能有些许的差异,不要紧,『习惯你自己的习惯』就好了。
你可以用 man bash (<a href="0320bash.html#ps3">注3</a>)去查找一下 PS1 的相关说明,以理解底下的一些符号意义。</p>
<ul style="font-family: '细明体'; padding-left: 30px; list-style-type: square">
<li>\d :可显示出『星期 月 日』的日期格式,如:"Mon Feb 2"</li>
<li>\H :完整的主机名称。举例来说,鸟哥的练习机为『study.centos.vbird』</li>
<li>\h :仅取主机名称在第一个小数点之前的名字,如鸟哥主机则为『study』后面省略</li>
<li>\t :显示时间,为 24 小时格式的『HH:MM:SS』</li>
<li>\T :显示时间,为 12 小时格式的『HH:MM:SS』</li>
<li>\A :显示时间,为 24 小时格式的『HH:MM』</li>
<li>\@ :显示时间,为 12 小时格式的『am/pm』样式</li>
<li>\u :目前用户的帐号名称,如『dmtsai』;</li>
<li>\v :BASH 的版本信息,如鸟哥的测试主机版本为 4.2.46(1)-release,仅取『4.2』显示</li>
<li>\w :完整的工作目录名称,由根目录写起的目录名称。但家目录会以 ~ 取代;</li>
<li>\W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。</li>
<li>\# :下达的第几个指令。</li>
<li>\$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~</li>
</ul>
<p>好了,让我们来看看 CentOS 缺省的 PS1 内容吧:『[\u@\h \W]\$ 』,现在你知道那些反斜线后的数据意义了吧?
要注意喔!那个反斜线后的数据为 PS1 的特殊功能,与 bash 的变量设置没关系啦!不要搞混了喔!
那你现在知道为何你的命令提示字符是:『 [dmtsai@study ~]$ 』了吧?好了,那么假设我想要有类似底下的提示字符:</p>
<blockquote class="text_import2">
[dmtsai@study /home/dmtsai 16:50 #12]$ </blockquote>
那个 # 代表第 12 次下达的指令。那么应该如何设置 PS1 呢?可以这样啊:<br>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">cd /home</span>
[dmtsai@study home]$ <span class="term_command">PS1='[\u@\h \w \A #\#]\$ '</span>
[dmtsai@study /home 17:02 #85]$
<span class="term_say"># 看到了吗?提示字符变了!变的很有趣吧!其中,那个 #85 比较有趣,
# 如果您再随便输入几次 ls 后,该数字就会增加喔!为啥?上面有说明滴!</span>
</pre></td></tr></tbody></table>
<ul><li>$:(关于本 shell 的 PID)</li></ul>
<p>钱字号本身也是个变量喔!这个咚咚代表的是『目前这个 Shell 的线程代号』,亦即是所谓的 PID (Process ID)。
更多的进程观念,我们会在第四篇的时候提及。想要知道我们的 shell 的 PID ,就可以用:『
echo $$ 』即可!出现的数字就是你的 PID 号码。</p>
<a id="returnvar"></a><ul><li>?:(关于上个运行指令的回传值)</li></ul>
<p>虾密?问号也是一个特殊的变量?没错!在 bash 里面这个变量可重要的很!
这个变量是:『<span class="text_import2">上一个运行的指令所回传的值</span>』,
上面这句话的重点是『上一个指令』与『回传值』两个地方。<span class="text_import2">当我们运行某些指令时,
这些指令都会回传一个运行后的代码。一般来说,如果成功的运行该指令,
则会回传一个 0 值</span>,如果运行过程发生错误,就会回传『错误代码』才对!一般就是以非为 0 的数值来取代。
我们以底下的例子来看看:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">echo $SHELL</span>
/bin/bash <span class="term_note"><==可顺利显示!没有错误!</span>
[dmtsai@study ~]$ <span class="term_command">echo $?</span>
0 <span class="term_note"><==因为没问题,所以回传值为 0</span>
[dmtsai@study ~]$ <span class="term_command">12name=VBird</span>
bash: 12name=VBird: command not found... <span class="term_note"><==发生错误了!bash回报有问题</span>
[dmtsai@study ~]$ <span class="term_command">echo $?</span>
127 <span class="term_note"><==因为有问题,回传错误代码(非为0)</span>
<span class="term_say"># 错误代码回传值依据软件而有不同,我们可以利用这个代码来搜索错误的原因喔!</span>
[dmtsai@study ~]$ <span class="term_command">echo $?</span>
0
<span class="term_say"># 咦!怎么又变成正确了?这是因为 "?" 只与『上一个运行指令』有关,
# 所以,我们上一个指令是运行『 echo $? 』,当然没有错误,所以是 0 没错!</span>
</pre></td></tr></tbody></table>
<ul><li>OSTYPE, HOSTTYPE, MACHTYPE:(主机硬件与核心的等级)</li></ul>
<p>我们在<a href="0105computers.html#pc_cpu">第零章、计算机概论内的 CPU 等级</a>说明中谈过 CPU ,
目前个人电脑的 CPU 主要分为 32/64 比特,其中 32 比特又可分为 i386, i586, i686,而 64 比特则称为 x86_64。
由于不同等级的 CPU 指令集不太相同,因此你的软件可能会针对某些 CPU 进行最佳化,以求取较佳的软件性能。
所以软件就有 i386, i686 及 x86_64 之分。以目前 (2015) 的主流硬件来说,几乎都是 x86_64 的天下!
因此 CentOS 7 开始,已经不支持 i386 兼容模式的安装光盘了~哇呜!进步的太快了!</p>
<p>要留意的是,较高端的硬件通常会向下兼容旧有的软件,但较高端的软件可能无法在旧机器上面安装!
我们在<a href="0130designlinux.html#beforeinstall_distro">第二章</a>就曾说明过,
这里再强调一次,你可以在 x86_64 的硬件上安装 i386 的 Linux 操作系统,但是你无法在 i686 的硬件上安装
x86_64 的 Linux 操作系统!这点得要牢记在心!</p>
</div>
<a id="export"></a>
<ul class="toplist"><li>export: 自订变量转成环境变量</li></ul>
<p>谈了 env 与 set 现在知道有所谓的环境变量与自订变量,那么这两者之间有啥差异呢?其实这两者的差异在于『
<span class="text_import2">该变量是否会被子进程所继续引用</span>』啦!唔!那么啥是父进程?子进程?
这就得要了解一下指令的下达行为了。</p>
<p>当你登录 Linux 并取得一个 bash 之后,你的 bash 就是一个独立的进程,这个进程的识别使用的是一个称为进程识别码,被称为 PID 的就是。
接下来你在这个 bash 底下所下达的任何指令都是由这个 bash 所衍生出来的,那些被下达的指令就被称为子进程了。
我们可以用底下的图标来简单的说明一下父进程与子进程的概念:</p>
<a id="fig10.2.3"></a>
<div style="text-align:center; margin: 0 auto 0 auto; "><img src="./vbird_files/ppid.gif" alt="进程相关性示意图" title="进程相关性示意图" style="border: 1px solid black; padding: 10px "></div>
<div style="text-align: center;">图10.2.3、进程相关性示意图</div>
<p>如上所示,我们在原本的 bash 底下运行另一个 bash ,结果操作的环境接口会跑到第二个 bash 去(就是子进程),
那原本的 bash 就会在暂停的情况 (睡着了,就是 sleep)。整个指令运作的环境是实线的部分!若要回到原本的 bash 去,
就只有将第二个 bash 结束掉 (下达 exit 或 logout) 才行。更多的进程概念我们会在第四篇谈及,这里只要有这个概念即可。</p>
<p>这个进程概念与变量有啥关系啊?关系可大了!因为<span class="text_import2">子进程仅会继承父进程的环境变量,
子进程不会继承父进程的自订变量</span>啦!所以你在原本 bash 的自订变量在进入了子进程后就会消失不见,
一直到你离开子进程并回到原本的父进程后,这个变量才会又出现!</p>
<p>换个角度来想,也就是说,如果我能将自订变量变成环境变量的话,那不就可以让该变量值继续存在于子进程了?
呵呵!没错!此时,那个 export 指令就很有用啦!如你想要让该变量内容继续的在子进程中使用,那么就请运行:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">export 变量名称</span>
</pre></td></tr></tbody></table>
<p>这东西用在『<span class="text_import2">分享自己的变量设置给后来调用的文件或其他进程</span>』啦!
像鸟哥常常在自己的主文件后面调用其他附属文件(类似函数的功能),但是主文件与附属文件内都有相同的变量名称,
若一再重复设置时,要修改也很麻烦,此时只要在原本的第一个文件内设置好『 export 变量 』,
后面所调用的文件就能够使用这个变量设置了!而不需要重复设置,这非常实用于 shell script 当中喔!
如果仅下达 export 而没有接变量时,那么此时将会把所有的『环境变量』秀出来喔!例如:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">export</span>
declare -x HISTSIZE="1000"
declare -x HOME="/home/dmtsai"
declare -x HOSTNAME="study.centos.vbird"
declare -x LANG="zh_TW.UTF-8"
declare -x LC_ALL="en_US.utf8"
<span class="term_say"># 后面的鸟哥就都直接省略了!不然....浪费版面~ ^_^</span>
</pre></td></tr></tbody></table>
<p>那如何将环境变量转成自订变量呢?可以使用本章后续介绍的 <a href="0320bash.html#declare">declare</a> 呢!</p>
<br></div><br>
<a id="variable_locale"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.2.4 影响显示结果的语系变量 (locale)</h2>
<p>还记得我们在<a href="0160startlinux.html#cmd_cmd_lang">第四章里面提到的语系问题</a>吗?
就是当我们使用 man command 的方式去查找某个数据的说明档时,该说明档的内容可能会因为我们使用的语系不同而产生乱码。
另外,利用 ls 查找文件的时间时,也可能会有乱码出现在时间的部分。那个问题其实就是语系的问题啦。</p>
<p>目前大多数的 Linux distributions 已经都是支持日渐流行的万国码了,也都支持大部分的国家语系。
那么我们的 Linux 到底支持了多少的语系呢?这可以由 locale 这个指令来查找到喔!</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">locale -a</span>
<span class="term_say">....(前面省略)....</span>
zh_TW
zh_TW.big5 <span class="term_note"><==大五码的中文编码</span>
zh_TW.euctw
zh_TW.utf8 <span class="term_note"><==万国码的中文编码</span>
zu_ZA
zu_ZA.iso88591
zu_ZA.utf8
</pre></td></tr></tbody></table>
<p>正体中文语系至少支持了两种以上的编码,一种是目前还是很常见的 big5 ,另一种则是越来越热门的 utf-8 编码。
那么我们如何修订这些编码呢?其实可以透过底下这些变量的说:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">locale</span> <span class="term_note"><==后面不加任何选项与参数即可!</span>
LANG=en_US <span class="term_note"><==主语言的环境</span>
LC_CTYPE="en_US" <span class="term_note"><==字符(文本)辨识的编码</span>
LC_NUMERIC="en_US" <span class="term_note"><==数字系统的显示消息</span>
LC_TIME="en_US" <span class="term_note"><==时间系统的显示数据</span>
LC_COLLATE="en_US" <span class="term_note"><==字符串的比较与排序等</span>
LC_MONETARY="en_US" <span class="term_note"><==币值格式的显示等</span>
LC_MESSAGES="en_US" <span class="term_note"><==消息显示的内容,如功能表、错误消息等</span>
LC_ALL= <span class="term_note"><==整体语系的环境</span>
<span class="term_say">....(后面省略)....</span>
</pre></td></tr></tbody></table>
<p>基本上,你可以逐一设置每个与语系有关的变量数据,但事实上,如果其他的语系变量都未设置,
且<span class="text_import2">你有设置 LANG 或者是 LC_ALL 时,则其他的语系变量就会被这两个变量所取代!</span>
这也是为什么我们在 Linux 当中,通常说明仅设置 LANG 或 LC_ALL 这两个变量而已,因为他是最主要的设置变量!
好了,那么你应该要觉得奇怪的是,为什么在 Linux 主机的终端机接口 (tty1 ~ tty6)
的环境下,如果设置『 LANG=zh_TW.utf8 』这个设置值生效后,使用 man 或者其他消息输出时,
都会有一堆乱码,尤其是使用 ls -l 这个参数时?</p>
<p>因为在 Linux 主机的终端机接口环境下是无法显示像中文这么复杂的编码文本,
所以就会产生乱码了。也就是如此,我们才会必须要在 tty1 ~ tty6 的环境下,
加装一些中文化接口的软件,才能够看到中文啊!不过,如果你是在 MS Windows
主机以远程连接服务器的软件连接到主机的话,那么,嘿嘿!其实文本接口确实是可以看到中文的。
此时反而你得要在 LC_ALL 设置中文编码才好呢!</p>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 无论如何,如果发生一些乱码的问题,那么设置系统里面保有的语系编码,
例如: en_US 或 en_US.utf8 等等的设置,应该就 OK 的啦!好了,那么系统缺省支持多少种语系呢?
当我们使用 locale 时,系统是列出目前 Linux 主机内保有的语系文件,
这些语系文件都放置在: <span class="text_import2">/usr/lib/locale/</span> 这个目录中。
</fieldset><br>
<p>你当然可以让每个用户自己去调整自己喜好的语系,但是整体系统缺省的语系定义在哪里呢?
其实就是在 /etc/locale.conf 啰!这个文件在 CentOS 7.x 的内容有点像这样:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">cat /etc/locale.conf</span>
LANG=zh_TW.utf8
LC_NUMERIC=zh_TW.UTF-8
LC_TIME=zh_TW.UTF-8
LC_MONETARY=zh_TW.UTF-8
LC_PAPER=zh_TW.UTF-8
LC_MEASUREMENT=zh_TW.UTF-8
</pre></td></tr></tbody></table>
<p>因为鸟哥在<a href="0157installcentos7.html">第三章的安装时</a>选择的是中文语系安装画面,
所以这个文件缺省就会使用中文编码啦!你也可以自行将他改成你想要的语系编码即可。</p>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 假设你有一个纯文本文件原本是在 Windows 底下创建的,那么这个文件缺省可能是 big5 的编码格式。
在你将这个文件上传到 Linux 主机后,在 X window 底下打开时,咦!怎么中文本通通变成乱码了?
别担心!因为如上所示, Linux 目前大多缺省是万国码显示嘛!你只要将开启该文件的软件编码由 utf8
改成 big5 就能够看到正确的中文了!
</fieldset><br>
<table class="exam"><tbody><tr><td>
例题:<div>
鸟哥原本是中文语系,所有显示的数据通通是中文。但为了网页显示的关系,需要将输出转成英文 (en_US.utf8) 的语系来展示才行。
但鸟哥又不想要写入设置档!毕竟是暂时显示用的~那该如何处理?</div>
答:<div>
其实不很难,重点是 LANG 及 LC_ALL 而已!但在 CentOS 7 当中,你要让 LC_ALL 生效时,得要使用 export 转成环境变量才行耶!
所以就是这样搞:
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">locale</span>
LANG=zh_TW.UTF-8
LC_CTYPE="zh_TW.UTF-8"
LC_NUMERIC="zh_TW.UTF-8"
LC_TIME="zh_TW.UTF-8"
[dmtsai@study ~]$ <span class="term_command">LANG=en_US.utf8; locale</span>
[dmtsai@study ~]$ <span class="term_command">export LC_ALL=en_US.utf8; locale</span> <span class="term_note"># 你就会看到与上头有不同的语系啰!</span>
</pre></td></tr></tbody></table>
</div>
</td></tr></tbody></table><br>
<br></div><br>
<a id="variable_range"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.2.5 变量的有效范围</h2>
<p>虾密?变量也有使用的『范围』?没错啊~我们在上头的 <a href="0320bash.html#export">export</a>
指令说明中,就提到了这个概念了。如果在跑程序的时候,有父进程与子进程的不同进程关系时,
则『变量』可否被引用与 export 有关。被 export 后的变量,我们可以称他为『环境变量』!
环境变量可以被子进程所引用,但是其他的自订变量内容就不会存在于子进程中。</p>
<fieldset class="vbirdface"><legend style="font-family: serif; font-size:12pt; color: darkblue;">Tips</legend><img src="./vbird_files/vbird_face.gif" alt="鸟哥的图标" title="鸟哥的图标" style="float: right;"> 在某些不同的书籍会谈到『全域变量, global variable』与『区域变量, local variable』。
在鸟哥的这个章节中,基本上你可以这样看待:<br>环境变量=全域变量<br>自订变量=区域变量
</fieldset><br>
<p>在学理方面,为什么环境变量的数据可以被子进程所引用呢?这是因为内存配置的关系!理论上是这样的:</p>
<ul style="padding-left: 25px">
<li>当启动一个 shell,操作系统会分配一记忆区块给 shell 使用,此内存内之变量可让子进程取用</li>
<li>若在父进程利用 export 功能,可以让自订变量的内容写到上述的记忆区块当中(环境变量);</li>
<li>当加载另一个 shell 时 (亦即启动子进程,而离开原本的父进程了),子 shell 可以将父 shell
的环境变量所在的记忆区块导入自己的环境变量区块当中。</li>
</ul>
<p>透过这样的关系,我们就可以让某些变量在相关的进程之间存在,以帮助自己更方便的操作环境喔!
不过要提醒的是,这个『环境变量』与『bash 的操作环境』意思不太一样,举例来说, PS1 并不是环境变量,
但是这个 PS1 会影响到 bash 的接口 (提示字符嘛)!相关性要厘清喔!^_^</p>
<br></div><br>
<a id="variable_read"></a>
<div class="block2"><div class="gototop"><a href="0320bash.html#top">Top</a></div>
<h2>10.2.6 变量键盘读取、数组与声明: read, array, declare</h2>
<p>我们上面提到的变量设置功能,都是由指令列直接设置的,那么,可不可以让用户能够经由键盘输入?
什么意思呢?是否记得某些程序运行的过程当中,会等待用户输入 "yes/no" 之类的消息啊?
在 bash 里面也有相对应的功能喔!此外,我们还可以声明这个变量的属性,例如:数组或者是数字等等的。底下就来看看吧!</p>
<a id="read"></a>
<ul class="toplist"><li>read</li></ul>
<p>要读取来自键盘输入的变量,就是用 read 这个指令了。这个指令最常被用在 shell script 的撰写当中,
想要跟用户对谈?用这个指令就对了。关于 script 的写法,我们会在第十三章介绍,底下先来瞧一瞧 read 的相关语法吧!</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">read [-pt] variable</span>
<span class="term_say">选项与参数:
-p :后面可以接提示字符!
-t :后面可以接等待的『秒数!』这个比较有趣~不会一直等待用户啦!</span>
<span class="term_hd">范例一:让用户由键盘输入一内容,将该内容变成名为 atest 的变量</span>
[dmtsai@study ~]$ <span class="term_command">read atest</span>
<span class="term_command">This is a test</span> <span class="term_note"><==此时光标会等待你输入!请输入左侧文本看看</span>
[dmtsai@study ~]$ <span class="term_command">echo ${atest}</span>
This is a test <span class="term_note"><==你刚刚输入的数据已经变成一个变量内容!</span>
<span class="term_hd">范例二:提示用户 30 秒内输入自己的大名,将该输入字符串作为名为 named 的变量内容</span>
[dmtsai@study ~]$ <span class="term_command">read -p "Please keyin your name: " -t 30 named</span>
Please keyin your name: <span class="term_command">VBird Tsai</span> <span class="term_note"><==注意看,会有提示字符喔!</span>
[dmtsai@study ~]$ <span class="term_command">echo ${named}</span>
VBird Tsai <span class="term_note"><==输入的数据又变成一个变量的内容了!</span>
</pre></td></tr></tbody></table>
<p>read 之后不加任何参数,直接加上变量名称,那么底下就会主动出现一个空白行等待你的输入(如范例一)。
如果加上 -t 后面接秒数,例如上面的范例二,那么 30 秒之内没有任何动作时,
该指令就会自动略过了~如果是加上 -p ,嘿嘿!在输入的光标前就会有比较多可以用的提示字符给我们参考!
在指令的下达里面,比较美观啦! ^_^</p>
<a id="declare"></a>
<ul class="toplist"><li>declare / typeset</li></ul>
<p>declare 或 typeset 是一样的功能,就是在『<span class="text_import2">声明变量的类型</span>』。如果使用
declare 后面并没有接任何参数,那么 bash 就会主动的将所有的变量名称与内容通通叫出来,就好像使用 set 一样啦!
那么 declare 还有什么语法呢?看看先:</p>
<table class="term"><tbody><tr><td class="term"><pre>[dmtsai@study ~]$ <span class="term_command">declare [-aixr] variable</span>
<span class="term_say">选项与参数:
-a :将后面名为 variable 的变量定义成为数组 (array) 类型
-i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型
-x :用法与 export 一样,就是将后面的 variable 变成环境变量;
-r :将变量设置成为 readonly 类型,该变量不可被更改内容,也不能 unset</span>
<span class="term_hd">范例一:让变量 sum 进行 100+300+50 的加总结果</span>
[dmtsai@study ~]$ <span class="term_command">sum=100+300+50</span>
[dmtsai@study ~]$ <span class="term_command">echo ${sum}</span>
100+300+50 <span class="term_note"><==咦!怎么没有帮我计算加总?因为这是文本型态的变量属性啊!</span>
[dmtsai@study ~]$ <span class="term_command">declare -i sum=100+300+50</span>
[dmtsai@study ~]$ <span class="term_command">echo ${sum}</span>
450 <span class="term_note"><==瞭乎??</span>
</pre></td></tr></tbody></table>
<p>由于在缺省的情况底下, bash 对于变量有几个基本的定义:</p>
<ul class="text_import2">
<li>变量类型缺省为『字符串』,所以若不指定变量类型,则 1+2 为一个『字符串』而不是『计算式』。
所以上述第一个运行的结果才会出现那个情况的;</li>
<li>bash 环境中的数值运算,缺省最多仅能到达整数形态,所以 1/3 结果是 0;</li>
</ul>
<p>现在你晓得为啥你需要进行变量声明了吧?如果需要非字符串类型的变量,那就得要进行变量的声明才行啦!
底下继续来玩些其他的 declare 功能。</p>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例二:将 sum 变成环境变量</span>
[dmtsai@study ~]$ <span class="term_command">declare -x sum</span>
[dmtsai@study ~]$ <span class="term_command">export | grep sum</span>
declare -ix sum="450" <span class="term_note"><==果然出现了!包括有 i 与 x 的声明!</span>
<span class="term_hd">范例三:让 sum 变成唯读属性,不可更动!</span>
[dmtsai@study ~]$ <span class="term_command">declare -r sum</span>
[dmtsai@study ~]$ <span class="term_command">sum=tesgting</span>
-bash: sum: readonly variable <span class="term_note"><==老天爷~不能改这个变量了!</span>
<span class="term_hd">范例四:让 sum 变成非环境变量的自订变量吧!</span>
[dmtsai@study ~]$ <span class="term_command">declare +x sum</span> <span class="term_note"><== 将 - 变成 + 可以进行『取消』动作</span>
[dmtsai@study ~]$ <span class="term_command">declare -p sum</span> <span class="term_note"><== -p 可以单独列出变量的类型</span>
declare -ir sum="450" <span class="term_note"><== 看吧!只剩下 i, r 的类型,不具有 x 啰!</span>
</pre></td></tr></tbody></table>
<p>declare 也是个很有用的功能~尤其是当我们需要使用到底下的数组功能时,
他也可以帮我们声明数组的属性喔!不过,老话一句,数组也是在 shell script 比较常用的啦!
比较有趣的是,如果你不小心将变量设置为『唯读』,通常得要注销再登录才能复原该变量的类型了! @_@</p>
<a id="array"></a>
<ul class="toplist"><li>数组 (array) 变量类型</li></ul>
<p>某些时候,我们必须使用数组来声明一些变量,这有什么好处啊?在一般人的使用上,
果然是看不出来有什么好处的!不过,如果您曾经写过程序的话,那才会比较了解数组的意义~
数组对写数值程序的设计师来说,可是不能错过学习的重点之一哩!好!不啰唆~
那么要如何设置数组的变量与内容呢?在 bash 里头,数组的设置方式是:</p>
<blockquote class="text_import2">var[index]=content</blockquote>
<p>意思是说,我有一个数组名称为 var ,而这个数组的内容为 var[1]=小明, var[2]=大明,
var[3]=好明 .... 等等,那个 index 就是一些数字啦,重点是用中刮号 ([ ]) 来设置的。
目前我们 bash 提供的是一维数组。老实说,如果您不必写一些复杂的程序,
那么这个数组的地方,可以先略过,等到有需要再来学习即可!因为要制作出数组,
通常与循环或者其他判断式交互使用才有比较高的存在意义!</p>
<table class="term"><tbody><tr><td class="term"><pre><span class="term_hd">范例:设置上面提到的 var[1] ~ var[3] 的变量。</span>
[dmtsai@study ~]$ <span class="term_command">var[1]="small min"</span>
[dmtsai@study ~]$ <span class="term_command">var[2]="big min"</span>
[dmtsai@study ~]$ <span class="term_command">var[3]="nice min"</span>
[dmtsai@study ~]$ <span class="term_command">echo "${var[1]}, ${var[2]}, ${var[3]}"</span>
small min, big min, nice min