The Linux Command Line学习笔记(四)

第二十一章:文本处理

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
这一章会重新拜访一些老朋友,并且会给我们介绍一些新朋友:
cat – 连接文件并且打印到标准输出
sort – 给文本行排序
uniq – 报告或者省略重复行
cut – 从每行中删除文本区域
paste – 合并文件文本行
join – 基于某个共享字段来联合两个文件的文本行
comm – 逐行比较两个有序的文件
diff – 逐行比较文件
tr – 翻译或删除字符
sed – 用于筛选和转换文本的流编辑器

cat
这个 cat 程序具有许多有趣的选项。其中许多选项用来帮助更好的可视化文本内容。一个例子是-A 选项, 其用来在文本中显示所有非打印字符。

[me@linuxbox ~]$ cat -A foo.txt
^IThe quick brown fox jumped over the lazy dog. $
[me@linuxbox ~]$
在输出结果中我们看到,这个 tab 字符在我们的文本中由^I 字符来表示,我们也看到一个$字符出现在文本行真正的结尾处, 表明我们的文本包含末尾的空格。

cat 程序也包含用来修改文本的选项。最著名的两个选项是-n,其给文本行添加行号和-s, 禁止输出多个空白行。

[me@linuxbox ~]$ cat > foo.txt
The quick brown fox


jumped over the lazy dog.
[me@linuxbox ~]$ cat -ns foo.txt #增加行号,删除多余的空白行
1 The quick brown fox
2
3 jumped over the lazy dog.
[me@linuxbox ~]$

sort
我们能够演示如何用 sort 程序来处理标准输入:
[me@linuxbox ~]$ sort > foo.txt

c
b
a
[me@linuxbox ~]$ cat foo.txt
a
b
c

表21-1: 常见的 sort 程序选项
| 选项 | 长选项 | 描述 |
|-------|-------|-------|
| -b | --ignore-leading-blanks | 默认情况下,从每行的第一个字符开始。这个选项从第一个非空白字符开始排序。 |
| -f | --ignore-case | 让排序不区分大小写。 |
| -n | --numeric-sort | 基于字符串的长度来排序
| -r | --reverse | 按相反顺序排序。结果按照降序排列,而不是升序。 |
| -k | --key=field1[,field2] | 对从 field1到 field2之间的字符排序,而不是整个文本行
| -o | --output=file | 把排好序的输出结果发送到文件,而不是标准输出。 |
| -t | --field-separator=char | 定义域分隔字符。

我们通过对 du 命令的输出结果排序来说明这个选项,du 命令可以 确定最大的磁盘空间用户,通常,这个du 命令列出的输出结果按照路径名来序:

[me@linuxbox ~]$ du -s /usr/share/\* | head
252 /usr/share/aclocal
96 /usr/share/acpi-support
8 /usr/share/adduser
...

[me@linuxbox ~]$ du -s /usr/share/* | sort -nr | head #根据长度反序排序
509940 /usr/share/locale-langpack
242660 /usr/share/doc
197560 /usr/share/fonts
这种排序起作用是 因为数值出现在每行的开头。但是如果我们想要基于文件行中的某个数值排序
忽略 ls 程序能按照文件大小对输出结果进行排序,我们也能够使用 sort 程序来完成此任务:
[me@linuxbox ~]$ ls -l /usr/bin | sort -nr -k 5 | head #空格和制表符作为分界符,所以是以第五个字段,文件大小来排序
-rwxr-xr-x 1 root root 8234216 2008-04-0717:42 inkscape
-rwxr-xr-x 1 root root 8222692 2008-04-07 17:42 inkview
...
在上面的例子中,我们指定 n 和 r 选项来执行相反的数值排序,并且指定 -k 5,让 sort 程序使用第五字段作为排序的关键值。

依赖多个关键值排序,例如 文件中的每一行都有三个字段:发行版的名称,版本号,和 MM/DD/YYYY 格式的发行日期:

SUSE 10.2 12/07/2006
Fedora 10 11/25/2008
SUSE 11.04 06/19/2008
Ubuntu 8.04 04/24/2008
...
为了解决这个问题,我们必须依赖多个键值来排序。sort 程序允许多个 -k 选项的实例,所以可以指定多个排序关键值。

[me@linuxbox ~]$ sort --key=1,1 --key=2n distros.txt
Fedora 5 03/20/2006
Fedora 6 10/24/2006
Fedora 7 05/31/2007
...
在第一个 key 选项的实例中, 我们指定了一个字段区域。因为我们只想对第一个字段排序,我们指定了 1,1, 意味着“始于并且结束于第一个字段。”在第二个实例中,我们指定了 2n,意味着第二个字段是排序的键值,选项字母和sort 程序的全局选项一样:b(忽略开头的空格),n(数值序),r(逆向排序),等等。
我们列表中第三个字段包含的日期格式不利于排序。在计算机中,日期通常设置为 YYYY-MM-DD 格式,这样使按时间顺序排序变得容易,但是我们的日期为美国格式 MM/DD/YYYY。那么我们怎样能按照 时间顺序来排列这个列表呢?幸运地是,sort 程序提供了一种方式。这个 key 选项允许在字段中指定偏移量,所以我们能在字段中 定义键值。
[me@linuxbox ~]$ sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt
Fedora 10 11/25/2008
Ubuntu 8.10 10/30/2008
SUSE 11.0 06/19/2008
...
通过指定 -k 3.7,我们指示 sort 程序使用一个排序键值,其始于第三个字段中的第七个字符,同样地,我们指定 -k 3.1和 -k 3.4来分离日期中的月和日。 我们也添加了 n 和 r 选项来实现一个逆向的数值排序。这个 b 选项用来删除日期字段中开头的空格( 行与行之间的空格数迥异,因此会影响 sort 程序的输出结果)。

一些文件不会使用 tabs 和空格做为字段界定符;例如,这个 /etc/passwd 文件,这个文件的字段之间通过冒号分隔开,所以我们怎样使用一个 key 字段来排序这个文件?sort 程序提供了一个 -t 选项来自定义分隔符。
[me@linuxbox ~]$ sort -t ':' -k 7 /etc/passwd | head # 以 : 为分隔符

uniq
与 sort 程序相比,这个 uniq 程序是个轻量级程序,uniq 会删除任意重复行,并且把结果发送到标准输出。 它常常和 sort 程序一
块使用,来清理重复的输出。
让我们创建一个文本文件,来实验一下:

[me@linuxbox ~]$ cat > foo.txt
a
b
c
a
b
c
住输入 Ctrl-d 来终止标准输入。现在,如果我们对文本文件执行 uniq 命令:

[me@linuxbox ~]$ uniq foo.txt
a
b
c
a
b
c
输出结果与原始文件没有差异;重复行没有被删除。实际上,uniq 程序能完成任务,其输入必须是排好序的数据,

[me@linuxbox ~]$ sort foo.txt | uniq
a
b
c
这是因为 uniq 只会删除相邻的重复行。uniq 程序有几个选项。这里是一些常用选项:
表21-2: 常用的 uniq 选项
| 选项 | 说明 |
|-------|-----|
| -c | 输出所有的重复行,并且每行开头显示重复的次数。 |
| -d | 只输出重复行,而不是特有的文本行。 |
| -i | 在比较文本行的时候忽略大小写。 |
| -u | 只是输出独有的文本行。这是默认的。 |

[me@linuxbox ~]$ sort foo.txt | uniq -c
2 a
2 b
2 c

切片和切块
cut
这个 cut 程序被用来从文本行中抽取文本,并把其输出到标准输出。从文本行中指定要抽取的文本有些麻烦,使用以下选项:
表21-3: cut 程序选择项
| 选项 | 说明 |
|-----|------|
| -c char_list | 从文本行中抽取由 char_list 定义的文本,也就是字符。
| -f field_list | 从文本行中抽取一个或多个由 field_list 定义的字段
| -d delim_char | 当指定-f 选项之后,使用 delim_char 做为字段分隔符
| --complement | 抽取整个文本行,除了那些由-c 和/或-f 选项指定的文本。 |
正如我们所看到的,cut 程序抽取文本的方式相当不灵活。cut 命令最好用来从其它程序产生的文件中 抽取文本,而不是从人们直接输入的文本中抽取。
如果我们使用带有 -A 选项的 cat 命令,我们能查看是否这个文件符号由 tab 字符分离字段的要求。
[me@linuxbox ~]$ cat -A distros.txt
SUSE^I10.2^I12/07/2006$ #看起来不错。字段之间仅仅是单个 tab 字符,没有嵌入空格
Fedora^I10^I11/25/2008$
SUSE^I11.0^I06/19/2008$
...
[me@linuxbox ~]$ cut -f 3 distros.txt #第三个字段
12/07/2006
11/25/2008
06/19/2008
04/24/2008
...
因为我们的 distros 文件是由 tab 分隔开的,最好用 cut 来抽取字段而不是字符。这是因为一个由 tab 分离的文件, 每行不太可能包含相同的字符数,这就使计算每行中字符的位置变得困难或者是不可能。然而, 我们已经抽取了一个字段,幸运地是其包含地日期长度相同,所以通过从每行中抽取年份,我们能展示怎样 来抽取字符:
[me@linuxbox ~]$ cut -f 3 distros.txt | cut -c 7-10
2006
2008
2007
...
通过对我们的列表再次运行 cut 命令,我们能够抽取从位置7到10的字符,其对应于日期字段的年份.
当操作字段的时候,有可能指定不同的字段分隔符,而不是 tab 字符。这里我们将会从/etc/passwd 文件中 抽取第一个字段:
[me@linuxbox ~]$ cut -d ':' -f 1 /etc/passwd | head #使用-d 选项,我们能够指定冒号做为字段分隔符。

paste
这个 paste 命令的功能正好与 cut 相反。它会添加一个或多个文本列到文件中,而不是从文件中抽取文本列
[me@linuxbox ~]$ paste distros-dates.txt distros-versions.txt #第二个文件粘贴在第一个文件后

join
一个 join操作通常与关系型数据库有关联,在关系型数据库中来自多个享有共同关键域的表格的 数据结合起来,得到一个期望的结果。这个 join 程序执行相同的操作
[me@linuxbox ~]$ join distros-key-names.txt distros-key-vernums.txt | head
这两个文件的日期是共同列,可以自动连接。同样,第二个文件链接到第一个文件后面

比较文本
comm
这个 comm 程序会比较两个文本文件,并且会显示每个文件特有的文本行和共有的文本行。通过使用 cat 命令,我们将会创建两个内容几乎相同的文本文件:

[me@linuxbox ~]$ cat > file1.txt
a
b
c
d
[me@linuxbox ~]$ cat > file2.txt
b
c
d
下一步,我们将使用 comm 命令来比较这两个文件:

[me@linuxbox ~]$ comm file1.txt file2.txt
a
b
c
d
e
正如我们所见到的,comm 命令产生了三列输出。第一列包含第一个文件独有的文本行;第二列, 文本行是第二列独有的;第三列包含两个文件共有的文本行。comm 支持 -n 形式的选项,这里 n 代表 1,2或 3。这些选项使用的时候,指定了要隐藏的列。例如,如果我们只想输出两个文件共享的文本行, 我们将隐藏第一列和第二列的输出结果:

[me@linuxbox ~]$ comm -12 file1.txt file2.txt
b
c
d

diff
类似于 comm 程序,diff 程序被用来监测文件之间的差异。软件开发员经常使用 diff 程序来检查不同程序源码 版本之间的更改,diff 能够递归地检查源码目录,经常称之为源码树。diff 程序的一个常见用例是 创建 diff 文件或者补丁,它会被其它程序使用,例如 patch 程序(我们一会儿讨论),来把文件 从一个版本转换为另一个版本。
如果我们使用 diff 程序,来查看我们之前的文件实例:

[me@linuxbox ~]$ diff file1.txt file2.txt
1d0
< a
4a4
> e
在默认格式中(不常用), 每组的更改之前都是一个更改命令,其形式为 range operation range , 用来描述要求更改的位置和类型,从而把第一个文件转变为第二个文件:
表21-4: diff 更改命令
| 改变 | 说明 |
|-----|--------|
| r1ar2 | 把第二个文件中位置 r2 处的文件行添加到第一个文件中的 r1 处。 |
| r1cr2 | 用第二个文件中位置 r2 处的文本行更改(替代)位置 r1 处的文本行。 |
| r1dr2 | 删除第一个文件中位置 r1 处的文本行,这些文本行将会出现在第二个文件中位置 r2 处。 |

常用的是上下文模式和统一模式(记住这个就行了)
当使用上下文模式(带上 -c 选项),我们将看到这些:

[me@linuxbox ~]$ diff -c file1.txt file2.txt
*** file1.txt 2008-12-23 06:40:13.000000000 -0500
--- file2.txt 2008-12-23 06:40:34.000000000 -0500
***************
*** 1,4 ****
- a
b
c
d
--- 1,4 ----
b
c
d
+ e
表21-5: diff 上下文模式更改指示符
| 指示符 | 意思 |
|-------|---------|
| blank | 上下文显示行。它并不表示两个文件之间的差异。 |
| - | 删除行。这一行将会出现在第一个文件中,而不是第二个文件内。 |
| + | 添加行。这一行将会出现在第二个文件内,而不是第一个文件中。 |
| ! | 更改行。将会显示某个文本行的两个版本,每个版本会出现在更改组的各自部分。 |

这个统一模式相似于上下文模式,但是更加简洁。通过 -u 选项来指定它:

[me@linuxbox ~]$ diff -u file1.txt file2.txt
--- file1.txt 2008-12-23 06:40:13.000000000 -0500
+++ file2.txt 2008-12-23 06:40:34.000000000 -0500
@@ -1,4 +1,4 @@
-a
b
c
d
+e
上下文模式和统一模式之间最显著的差异就是重复上下文的消除
表21-6: diff 统一模式更改指示符
| 字符 | 意思 |
|-----|-------|
| 空格 | 两个文件都包含这一行。 |
| - | 在第一个文件中删除这一行。 |
| + | 添加这一行到第一个文件中。 |

patch
Linux 内核是由一个 大型的,组织松散的贡献者团队开发而成,这些贡献者会提交固定的少量更改到源码包中。 这个 Linux 内核由几百万行代码组成,虽然每个贡献者每次所做的修改相当少。对于一个贡献者 来说,每做一个修改就给每个开发者发送整个的内核源码树,这是没有任何意义的。相反, 提交一个 diff 文件。一个 diff 文件包含先前的内核版本与带有贡献者修改的新版本之间的差异。 然后一个接受者使用 patch 程序,把这些更改应用到他自己的源码树中。

运行时编辑
tr
这个 tr 程序被用来更改字符。我们可以把它看作是一种基于字符的查找和替换操作。我们可以通过 tr 命令来执行这样的转换,如下所示:
[me@linuxbox ~]$ echo "lowercase letters" | tr a-z A-Z
LOWERCASE LETTERS
tr 命令接受两个参数:要被转换的字符集以及 相对应的转换后的字符集。
tr 也可以完成另一个技巧。使用-s 选项,tr 命令能“挤压”(删除)重复的字符实例:
[me@linuxbox ~]$ echo "aaabbbccc" | tr -s ab
abccc
这里我们有一个包含重复字符的字符串。通过给 tr 命令指定字符集“ab”,我们能够消除字符集中 字母的重复实例,然而会留下不属于字符集的字符(“c”)无更改。注意重复的字符必须是相邻的, 如果它们不相邻,那么挤压会没有效果,例如:
[me@linuxbox ~]$ echo "abcabcabc" | tr -s ab
abcabcabc

sed
名字 sed 是 stream editor(流编辑器)的简称。它对文本流进行编辑,要不是一系列指定的文件, 要不就是标准输入。这里有一个非常简单的 sed 实例:
[me@linuxbox ~]$ echo "front" | sed 's/front/back/'
back
在这个例子中,我们使用 echo 命令产生了一个单词的文本流,然后把它管道给 sed 命令。sed,依次,对流文本执行指令 s/front/back/,随后输出“back”。这个替换命令由字母 s 来代表,其后跟着查找 和替代字符串,斜杠字符做为分隔符。分隔符的选择是随意的。按照惯例,经常使用斜杠字符。

sed 中的大多数命令之前都会带有一个地址,其指定了输入流中要被编辑的文本行。如果省略了地址, 然后会对输入流的每一行执行编辑命令。最简单的地址形式是一个行号。我们能够添加一个地址 到我们例子中:
[me@linuxbox ~]$ echo "front" | sed '1s/front/back/'
back
给我们的命令添加地址 1,就导致只对仅有一行文本的输入流的第一行执行替换操作。如果我们指定另一个数字:
[me@linuxbox ~]$ echo "front" | sed '2s/front/back/'
front
我们看到没有执行这个编辑命令,因为我们的输入流没有第二行。地址可以用许多方式来表达。这里是 最
常用的:
表21-7: sed 地址表示法
| 地址 | 说明 |
|-----|-------|
| n | 行号,n 是一个正整数。 |
| $ | 最后一行。 |
| /regexp/ | 所有匹配一个 POSIX 基本正则表达式的文本行
| addr1,addr2 | 从 addr1 到 addr2 范围内的文本行,包含地址 addr2 在内。地址可能是上述任意 单独
的地址形式。 |
| first~step | 匹配由数字first代表的文本行,然后随后的每个在 step 间隔处的文本行。例如 5~5 则指第五行和之后每五行位置的文本。行。 |
| addr1,+n | 匹配地址 addr1 和随后的 n 个文本行。 |
| addr! | 匹配所有的文本行,除了 addr 之外
通过使用这一章中早前的 distros.txt 文件,我们将演示不同种类的地址表示法。首先,一系列行号:
[me@linuxbox ~]$ sed -n '1,5p' distros.txt
SUSE 10.2 12/07/2006
Fedora 10 11/25/2008
SUSE 11.0 06/19/2008
Ubuntu 8.04 04/24/2008
Fedora 8 11/08/2007
在这个例子中,我们打印出一系列的文本行,开始于第一行,直到第五行。为此,我们使用 p 命令, 其就是简单地把匹配的文本行打印出来。然而为了高效,我们必须包含选项 -n(不自动打印选项), 让sed 不要默认地打印每一行。

下一步,我们将试用一下正则表达式:
[me@linuxbox ~]$ sed -n '/SUSE/p' distros.txt # 斜杠界定的正则表达式
SUSE 10.2 12/07/2006
SUSE 11.0 06/19/2008
SUSE 10.3 10/04/2007
SUSE 10.1 05/11/2006
最后,我们将试着否定上面的操作,通过给这个地址添加一个感叹号:
[me@linuxbox ~]$ sed -n '/SUSE/!p' distros.txt
Fedora 10 11/25/2008
Ubuntu 8.04 04/24/2008
Fedora 8 11/08/2007
Ubuntu 6.10 10/26/2006
这里我们看到期望的结果:输出了文件中所有的文本行,除了那些匹配这个正则表达式的文本行。
目前为止,我们已经知道了两个 sed 的编辑命令,s 和 p。这里是一个更加全面的基本编辑命令列表:
表21-8: sed 基本编辑命令
| 命令 | 说明 |
|-----|-------|
| = | 输出当前的行号。 |
| a | 在当前行之后追加文本。 |
| d | 删除当前行。 |
| i | 在当前行之前插入文本。 |
| p | 打印当前行。默认情况下,sed 程序打印每一行,并且只是编辑文件中匹配指定地址的文本行。通过指定-n 选项,这个默认的行为能够被略。 |
| q | 退出 sed,不再处理更多的文本行。如果不指定-n 选项,输出当前行。 |
| Q | 退出 sed,不再处理更多的文本行。 |
| s/regexp/replacement/ | 只要找到一个 regexp 匹配项,就替换为 replacement 的内

到目前为止,这个 s 命令是最常使用的编辑命令。
[me@linuxbox ~]$ echo "aaabbbccc" | sed 's/b/B/'
aaa Bbbccc
我们看到虽然执行了替换操作,但是只针对第一个字母 “b” 实例,然而剩余的实例没有更改。通过添加g 标志, 我们能够更改所有的实例:
[me@linuxbox ~]$ echo "aaabbbccc" | sed 's/b/B/g'

第二十二章:格式化输出

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
在这章中,我们继续着手于文本相关的工具,关注那些用来格式化输出的程序,而不是改变文本自身。    这些工具通常让文本准备就绪打印,这是我们在下一章会提到的。
nl - 添加行号
nl 程序是一个相当神秘的工具,用作一个简单的任务。它添加文件的行数。在它最简单的用途中,它相当于 cat -n:

[me@linuxbox ~]$ nl distros.txt | head

1 Fedora 5 2006-03-20
2 Fedora 6 2006-10-24
3 Fedora 7 2007-05-31

fold - 限制文件行宽

[me@linuxbox ~]$ echo "The quick brown fox jumped over the lazy dog." | fold -w 12
The quick br
own fox jump
ed over the
lazy dog.
我们设定了行宽为12个字符。 如果没有字符设置,默认是80。注意到文本行不会因为单词边界而不会被分解。增加的 -s 选项将让 fold 分解到最后可用的空白 字符,即会考虑单词边界。

[me@linuxbox ~]$ echo "The quick brown fox jumped over the lazy dog."
| fold -w 12 -s
The quick
brown fox
jumped over
the lazy
dog.

第二十三章:打印

非目前学习重点

第二十四章:编译程序

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
用高级语言编写的程序,经过另一个称为编译器的程序的处理,会转换成机器语言。一些编译器把    高级指令翻译成汇编语言,然后使用一个汇编器完成翻译成机器语言的最后阶段。
Python脚本在Linux上怎么运行?
[root@qiansw tmp]# cat test.py #这是一个python示例程序
1
2
3
#!/usr/bin/python
for i in range(0,5):
print i
[root@qiansw tmp]# ll
total 48
-rw-r--r-- 1 root root 48 Oct 30 11:04 test.py
[root@qiansw tmp]# chmod +x test.py #为脚本增加执行权限,另外一种表达[root@qiansw tmp]# chmod 755 test.py #为脚本增加执行权限
[root@qiansw tmp]# ./test.py #这是第一种方法
0
1
2
3
4
[root@qiansw tmp]# python test.py #这是第二种方法,不用增加执行权限
0
1
2
3
4

有两种方式:
1、直接使用python xxxx.py执行。其中python可以写成python的绝对路径。使用which python进行查询。
2、在文件的头部(第一行)写上#!/usr/bin/python2.7,这个地方使用python的绝对路径,就是上面用which python查询来的结果。然后在外面就可以使用./xxx.py执行了。
因为在linux中,python啊shell这些程序都是普通的文本格式,都需要一种程序去解释执行它。要么调用的时候指定,要么在文件头指定。

第二十五章:编写第一个shell脚本

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
最简单的解释,一个    shell    脚本就是一个包含一系列命令的文件。shell    读取这个文件,然后执行    文件中的所有命令,就好像这些命令已经直接被输入到了命令行中一样。

我们把此脚本文件保存为 hello_world。
下一步我们要做的事情是让我们的脚本可执行。使用 chmod 命令,这很容易做到:
[me@linuxbox ~]$ ls -l hello_world
-rw-r--r-- 1 me me 63 2009-03-07 10:10 hello_world
[me@linuxbox ~]$ chmod 755 hello_world
[me@linuxbox ~]$ ls -l hello_world
-rwxr-xr-x 1 me me 63 2009-03-07 10:10 hello_world
对于脚本文件,有两个常见的权限设置;权限为755的脚本,则每个人都能执行,和权限为700的 脚本,
只有文件所有者能够执行。

脚本文件位置
当设置了脚本权限之后,我们就能执行我们的脚本了:
[me@linuxbox ~]$ ./hello_world
Hello World!
为了能够运行此脚本,我们必须指定脚本文件明确的路径。如果我们没有那样做,我们会得到这样的提示:
[me@linuxbox ~]$ hello_world
bash: hello_world: command not found

回到第12章,我们讨论了 PATH 环境变量及其它在系统 查找可执行程序方面的作用。回顾一下,如果没有给出可执行程序的明确路径名,那么系统每次都会 搜索一系列的目录,来查找此可执行程序。这个/bin 目录就是其中一个系统会自动搜索的目录。 这个目录列表被存储在一个名为PATH 的环境变量中。

大多数的 Linux 发行版会配置 PATH 变量,让其包含一个位于用户家目录下的 bin 目录,从而允许用户能够执行他们自己的程序。所以如果我们创建了 一个bin 目录,并把我们的脚本放在这个目录下,那么这个脚本就应该像其它程序一样开始工作了:
[me@linuxbox ~]$ mkdir bin
[me@linuxbox ~]$ mv hello_world bin #移动到用户家目录下的bin目录下
[me@linuxbox ~]$ hello_world
Hello World!

如果这个 PATH 变量不包含这个目录(记住以下两个命令就可以了),我们能够轻松地添加它,通过在我们的.bashrc 文件中包含下面 这一行文本:

export PATH=~/bin:"$PATH"
当做了这个修改之后,它会在每个新的终端会话中生效。为了把这个修改应用到当前的终端会话中, 我们必须让 shell 重新读取这个 .bashrc 文件。这可以通过 “sourcing”.bashrc 文件来完成:

[me@linuxbox ~]$ . .bashrc

脚本文件的好去处
这个 ~/bin 目录是存放为个人所用脚本的好地方。如果我们编写了一个脚本,系统中的每个用户都可以使用它, 那么这个脚本的传统位置是 /usr/local/bin。系统管理员使用的脚本经常放到 /usr/local/sbin 目录下。 大多数情况下,本地支持的软件,不管是脚本还是编译过的程序,都应该放到 /usr/local 目录下,而不是在 /bin 或 /usr/bin 目录下。这些目录都是由 Linux 文件系统层次结构标准指定,只包含由 Linux发行商 所提供和维护的文件。
-------------Thanks for Reading!-------------