鸟哥的Linux私房菜-第10/11/12/13章(vim程序编辑器、学习bash、正则表达式与文件格式化处理、学习Shell Scripts)

2023-07-29,,

第10章 vim程序编辑器

可以将vim看做vi的进阶版本,vim可以用颜色或底线等方式来显示出一些特殊的信息。

为何要学习vim?因为:

  a. 所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在;

  b. 很多个别软件的编辑接口都会主动呼叫 vi (例如未来会谈到的 crontab, visudo, edquota 等指令);

  c. vim 具有程序编辑的能力,可以主动的以字体颜色辨别语法的正确性,方便程序设计;
  d. 因为程序简单,编辑速度相当快速。

vi的使用

vi的三种模式:一般模式、编辑模式、指令列命令模式。

按键说明

第一部分:一般模式可用的按钮说明,光标移动、复制贴上、搜寻取代等

第二部分:一般模式切换到编辑模式的可用按键说明

第三部分:一般模式切换到指令列模式的可用按键说明

注意:在 vi 中,数字很有意义。数字通常代表重复做几次,也可能代表去到第几行。

vim 的暂存档、救援回复与开启时的警告信息

当我们在使用 vim 编辑时, vim 会在与被编辑的档案的目录下,再建立一个名为 .filename.swp 档案。 比如,编辑 /tmp/vitest/man.config 这个档案时, vim 会主动的建立/tmp/vitest/.man.config.swp 暂存档,你对 man.config 做的动作就会被记录到这个 .man.config.swp 当中。如果你的系统因为某些原因断线了, 导致你编辑的档案还没有储存,这个时候 .man.config.swp 就能够发挥救援的功能。

由与暂存盘存在的关系,因此 vim 会主动判断你的这个档案可能有些问题,在上面的图示中 vim 提示两点主要的问题与解决方案,分别是这样的:
  问题一:可能有其他人或程序同时在编辑这个档案:
由与 Linux 是多人多任务的环境,因此很可能有很多人同时在编辑同一个档案。如果在多人共同编辑的情况下, 万一大家同时储存,那么这个档案的内容将会变的乱七八糟!为了避免这个问题,因此 vim 会出现这个警告窗口! 解决的方法则是:
  a. 找到另外那个程序或人员,请他将该 vim 的工作结束,然后你再继续处理。
  b. 如果你只是要看该档案的内容并的会有任何修改编辑癿行为,那么可以选择开启成为只读(O)档案, 亦即上述画面反白部分输入英文『 o 』即可,其实就是 [O]pen Read-Only癿选项啦!
  问题二:在前一个 vim 癿环境中,可能因为某些丌知名原因导致 vim 中断 (crashed):

这就是常见的不正常结束 vim 产生的后果。解决方案依据吧同癿情况而不同喔!常见的处理方法为:
  a. 如果你之前的 vim 处理动作尚未储存,此时你应该要按下『R』,亦即使用 (R)ecover 的项目, 此时 vim 会载入 .man.config.swp 的内容,让你自己来决定要不要储存!这样就能够救回来你之前未储存的工作。 不过那个 .man.config.swp 并不会在你结束 vim 后自动删除,所以你离开 vim 后还得要自行删除 .man.config.swp 才能避免每次打开这个档案都会出现这样的警告!
  b. 如果你确定这个暂存盘是没有用的,那么你可以直接按下『D』删除掉这个暂存盘,亦即(D)elete it 这个项目即可。 此时 vim 会载入 man.config ,并且将旧的 .man.config.swp 删除后,建立这次会使用新的 .man.config.swp 喔!

至与这个发现暂存盘警告讯息的画面中,有出现六个可用按钮,各按钮的说明如下:

  a.  [O]pen Read-Only:打开此档案成为只读档, 可以用在你只是想要查阅该档案内容并不想要进行编辑行为时。一般来说,在上课时,如果你是登入到同学的计算机去看他的配置文件, 结果发现其实同学他自己也在编辑时,可以使用这个模式;
  b. (E)dit anyway:还是用正常的方式打开你要编辑的那个档案, 并布会载入暂存盘的内容。不过很容易出现两个使用者互相改变对方的档案等问题!不好不好!
  c. (R)ecover:就是加载暂存盘的内容,用在你要救回之前未储存的工作。 不过当你救回来并且储存离开 vim 后,还是要手动自行删除那个暂存档喔!
  d. (D)elete it:你确定那个暂存档是无用的!那么开启档案前会先将这个暂存盘删除! 这个动作其实是比较常做的!因为你可能不确定这个暂存档是怎么来的,所以就删除掉他吧!哈哈!
  e. (Q)uit:按下 q 就离开 vim ,不会进行任何动作回到命令提示字符。
  f. (A)bort:忽略这个编辑行为,感觉上与 quit 非常类似! 也会送你回到命令提示字符就是啰!

vim 的额外功能

区块选择(Visual Block)

多文档编辑

vim 后面同时接多个档案同时开启。相关按键:

多窗口功能

vim 环境设定与记录:~/.vimrc, ~/.viminfo

在 vim 做过的动作都会被记录在 ~/.viminfo 这个档案中。

vim 的环境设定参数有很多,如果你想要知道目前的设定值,可以在一般模式时输入【:set all】查询。常用的设定值:

我们可以透过配置文件来直接规定我们习惯的 vim 操作环境呢! 整体 vim 的设定值一般是放置在 /etc/vimrc 这个档案,不过,不建议你修改他! 你可以修改 ~/.vimrc 这个档案(预设不存在,请你自行手动建立!),将你所希望的设定值写入! 举例来说,可以是这样的一个档案:

vim 常用指令示意图

其他 vim 使用注意事项

中文编码问题

1. 你的 Linux 系统默人支持的语系数据:这与 /etc/sysconfig/i18n 有关;
2. 你的终端界面 (bash) 的语系: 这与 LANG 这个变量有关;
3. 你的档案原本的编码;
4. 开启终端机癿的软件,例如在 GNOME 底下的窗口接口。

事实上最重要的是上面的第三和第四点,只要这两点的编码一致,你就能够正确的看到与编辑你的中文档案。 否则就会看到一堆乱码啦!

DOS 与 Linux 的断行字符

DOS 与 Linux 断行字符的不同。 我们也可以利用 cat -A 来观察以 DOS (Windows 系统) 建立的档案的特殊格式, 也可以发现在 DOS 使用的断行字
符为 ^M$ ,我们称为 CR 与 LF 两个符号。 而在 Linux 底下,则是仅有 LF ($) 这个断行符号。这个断行符号对与 Linux 的影响很大喔!

在 Linux 底下的指令在开始执行时,他的判断依据是 『Enter』,而 Linux 的 Enter 为 LF符号, 不过,由与 DOS 的断行符号是 CRLF ,也就是多了一个 ^M 的符号出来, 在这样的情况下,如果是一个 shell script 的程序档案,将可能造成『程序无法执行』的状态, 因为他会误判程序所下达的指令内容啊。

那则么办啊?很简单啊,将格式转换成为 Linux 即可。

如果在不同系统之间复制一些纯文本档案时,千万记得要使用 unix2dos 或 dos2unix 来转换一下断行格式。

eg: unix2dos -k man.config  将man.config修改成dos断行

  dos2unix -k man.config man.config.linux  将man.config转成man.config.linux断行字符

语系编码转换

第11章 学习 bash

认识 bash 这个 shell

管理整个计算机硬件的其实是操作系统的核心 (kernel),这个核心是需要被保护的! 所以我们一般使用者就只能透过 shell 来跟核心沟通,以让核心达到我们所想要达到的工作。 那么系统有多少 shell 可用呢?为什么我们要使用 bash 啊?

硬件、核心与 shell

其实壳程序的功能只是提供用户操作系统的一个接口,因此这个壳程序需要可以呼叫其他软件才好。 我们学过很多指令,包括 man, chmod, chown, vi, fdisk, mkfs 等等指令,这些指令都是独立的应用程序, 但是我们可以透过壳程序 (就是指令列模式) 来操作这些应用程序,让这些应用程序呼叫核心来运作所需的工作。

为何要学文字接口的 shell ?

文字接口的 shell :几乎各家 distributions 使用的bash都是一样的;

远程管理:文字接口比较快;

Linux 的任督二脉: shell 是也!

系统的合法 shell 与 /etc/shells 功能

目前我们的 Linux (以 CentOS 5.x 为例) 有多少我们可以使用的 shells 呢? 你可以检查一下
/etc/shells 这个档案,至少就有底下这几个可以用的 shells:
   /bin/sh (已经被 /bin/bash 所取代)
   /bin/bash (就是 Linux 预设的 shell)
   /bin/ksh (Kornshell 由 AT&T Bell lab. 发展出来的,兼容与 bash)
   /bin/tcsh (整合 C Shell ,提供更多的功能)
   /bin/csh (已经被 /bin/tcsh 所取代)
   /bin/zsh (基于 ksh 发展出来的,功能更强大的 shell)

为什么我们系统上合法的 shell 要写入 /etc/shells 这个档案啊? 这是因为系统某些朋务在运作过程中,会去检查使用者能够使用的 shells ,而这些 shell 的查询就是藉由 /etc/shells 这个档案啰!

登入取得的 shell 记录在 /etc/passwd 这个档案中。

bash shell 的功能

命令编修能力(history):

  bash 的功能里头,相当棒的一个就是『他能记忆使用过的指令!』
因为我只要在指令列按『上下键』就可以找到前/后一个输入的指令!而在很多 distribution 里头,默认的指令记忆功能可以到达 1000 个!也就是说, 你曾经下达过的指令几乎都被记录下来了。

  这么多的指令记录在哪里呢?在你的家目录内的 .bash_history 啦! 不过,需要留意的是,~/.bash_history 记录的是前一次登入以前所执行过的指令, 而至于这一次登入所执行的指令都被暂存在内存中,当你成功注销系统后,该指令记忆才会记录到 .bash_history 当中!

命令与档案补全功能: ([tab] 按键的好处)

  【tab】这个按键的功能就是在 bash 里面才有。

命令别名设定功能:alias

工作控制、前景背景控制: (job control, foreground, background)

程序脚本化:shell scripts

通配符:Wildcard

bash shell 的内建命令:type

为了方便 shell 操作,bash已经内建了很多指令,比如 cd, umask等。

那我怎么知道这个指令是来自外部指令(指的是其他非 bash 所提供得指令) 或是内建在 bash 当中的呢?

指令的下达

shell 的变量功能

什么是变量

什么是『变量』呢?简单的说,就是让某一个特定字符串代表不固定的内容就是了。

最大的好处就是『方便!』:

  变量的可变性与方便性;

  影响 bash 环境操作的变量;

  脚本程序设计(shell script)的好帮手

变量的取用与设定:echo,变量设定规则,unset

变量的取用:echo

变量的设定规则

1. 变量与变量内容以一个等号『=』来连结,如下所示:
『myname=VBird』
2. 等号两边不能直接接空格符,如下所示为错误:
『myname = VBird』或『myname=VBird Tsai』
3. 变量名称只能是英文字母与数字,但是开头字符不能是数字,如下为错误:
『2myname=VBird』
4. 变量内容若有空格符可使用双引号『"』或单引号『'』将发量内容结合起来,但双引号内的特殊字符如 $ 等,可以保有原本的特性,如下所示:
『var="lang is $LANG"』则『echo $var』可得『lang is en_US』
  单引号内的特殊字符则仅为一般字符 (纯文本),如下所示:
『var='lang is $LANG'』则『echo $var』可得『lang is $LANG』
5. 可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, \, 空格符, '等)变成一般字符;
6. 在一串指令中,还需要藉由其他的指令提供的信息,可以使用反单引号『`指令`』或 『$(指令)』。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号! 例如想要取得核心版本的设定:
『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』
7. 若该变量为扩增变量内容时,则可用 "$发量名称" 或 ${变量} 累加内容,如下所示:
『PATH="$PATH":/home/bin』
8. 若该发变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量:
『export PATH』
9. 通常大写字符为系统默认变量,自行设定变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好) ;
10. 取消变量的方法为使用 unset :『unset 变量名称』例如取消 myname 的设定:
『unset myname』

举例:

什么是『子程序』呢?就是说,在我目前这个 shell 的情况下,去启用另一个新的 shell ,新的那个shell 就是子程序啦!在一般的状态下,父程序的自定义变量是无法在子程序内使用的。但是透过export 将变量变成环境变量后,就能够在子程序底下应用了!

环境变量的功能

环境变量可以帮我们达到很多功能~包括家目录的变换啊、提示字符的显示啊、执行文件搜寻的路径等。

目前我的shell 环境中, 有多少默认的环境变量啊?我们可以到用两个指令来查阅,分别是 env 与 export 呢!

用 env 观察环境变量与常见环境变量说明

上面这些变量有些什么功用呢?底下我们就一个一个来分析:

 HOME
代表用户的家目录。还记得我们可以使用 cd ~ 去到自己的家目录吗?或者利用 cd 就可以直接回到用户家目录了。那就是取用这个变量啦~ 有很多程序都可能会取用动这个变量的值!
 SHELL
告知我们,目前这个环境使用的 SHELL 是哪支程序? Linux 预设使用 /bin/bash 的啦!
 HISTSIZE
这个与『历史命令』有关,亦即是, 我们曾经下达过的指令可以被系统记录下来,而记录的『笔数』则是由这个值来设定的。
 MAIL
当我们使用 mail 这个指令在收信时,系统会去读取得邮件信箱档案 (mailbox)。
 PATH
就是执行文件搜寻的路径啦~目录与目录中间以冒号(:)分割, 由于档案的搜寻是依序由 PATH 的变量内的目录来查询,所以,目录的顺序也是重要的喔。
 LANG
这个重要!就是语系数据啰~徆多讯息都会用到他, 举例来说,当我们在启动某些 perl 的程序语言档案时,他会主动的去分析语系数据文件, 如果发现有他无法解析的编码语系,可能会产生错误喔!一般来说,我们中文编码通常是 zh_TW.Big5 或者是 zh_TW.UTF-8,这两个编码偏偏不容易被解译出来,所以,有的时候,可能需要修订一下语系数据。
 RANDOM
这个玩意儿就是『随机随机数』的发量啦!目前大多数的 distributions 都会有随机数生成器,那就是 /dev/random 这个档案。 我们可以透过这个随机数档案相关的变量 ($RANDOM) 来随机取得随机数值喔。在 BASH 癿环境下,这个 RANDOM 变量的内容,介于 0~32767 之间,所以,你只要 echo $RANDOM 时,系统就会主劢动的随机取出一个介于 0~32767 的数值。万一我想要使用 0~9 之间的数值呢?呵呵~利用 declare 宣告数值类型, 然后这样做就可以了:

用 set 观察所有变量 (含环境变量和自定义变量)

bash 可不止有环境变量,还有一些与 bash 操作接口有的变发量,以及用户自己定义的变量存在。那么这些变量如何观察呢?这个时候就得要使用 set 这个指令了。 set 除了环境变量之外, 还会将其他在 bash 内的变量通通显示出来。信息很多,仅列出几个重要的内容:

一般来说,不论是否为环境变量,只要跟我们目前这个 shell 的操作接口有关的变量, 通常都会被设定为大写字符,也就是说,『基本上,在 Linux 预设的情况中,使用{大写的字母}来设定的变量一般为系统内定需要的变量』。有哪些是比较重要的?

  PS1:提示字符的设定

  $:关于本 shell 的PID

  ?:关于上个执行指令的回传值

  OSTYPE, HOSTTYPE, MACHTYPE:主机硬件与核心的等级

export:自定义变量转成环境变量

环境变量与自定义变量的区别:该变量是否会被子程序继续引用。子程序仅会继承父程序的环境变量,不会继承自定义变量。

登入Linux并取得一个 bash 后,bash 就是一支独立的程序,被称为PID的就是。接下来你在这个 bash 底下所下达的任何指令都是由这个 bash 所衍生出来的,那些被下达的指令 就称为子程序。

把自定义变量变成环境变量:语法:export 变量名称

影响显示结果的语系变量(locale)

查询linux支持的语系(/usr/lib/locale):

修订编码:

系统默认的语系定义在:/etc/sysconfig/i18n

变量的有效范围

为什么环境变量的数据可以被子程序所引用呢?这是因为内存配置的关系!理论上是这样的:
   当启动一个 shell,操作系统会分配一记忆区块给 shell 使用,此内存内变量可让子程序取用
   若在父程序用 export 功能,可以让自定义变量的内容写到上述的记忆区块当中(环境变量);
   当加载另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变量所在的记忆区块导入自己的环境发量区块当中

变量键盘读取、数组与宣告:read, array, declare

read:读取来至键盘输入的变量

declare/typeset

declare 或 typeset 是一样的功能,就是在『宣告变量的类型』。如果使用 declare 后面并没有接任何参数,那么 bash 就会主动的将所有的变量名称与内容通通叫出来,就好像使用 set 一样。

如果你不小心将变量设定为『只读』,通常得要注销再登入才能复原该变量的类型。

数组(array)变量类型

在 bash 里面,数组的设定方式:arrayName[index]=content

与文件系统及程序的限制关系:ulimit

我们的 bash 是可以『限制用户的某些系统资源』癿,包括可以开启的档案数量, 可以使用的 CPU时间,可以使用的内存总量等等。如何设定?用 ulimit 吧!

变量内容的删除、取代与替换

变量内容的删除与取代

变量的测试与内容替换

命令别名与历史命令:

命令别名设定:alias, unalias

历史命令:history

bash shell 的操作环境:

路径与指令搜寻顺序

bash 的进站与欢迎信息:/etc/issue, /etc/motd

bash 的环境配置文件

终端机的环境设定:stty, set

通配符与特殊符号

数据流重导向

数据流重导向就是将某个指令执行后应该要出现在屏幕上的数据,传递到其他地方。

什么是数据流重导向?

简单的说,标准输出指的是『指令执行所回传的正确的讯息』,而标准错误输出可理解为『 指令执行失败后,所回传的错误讯息』。

standard output 与 standard error output

数据流重导向可以将 standard output(简称 stdout) 与 standard error output (简称 stderr) 分别传送到其他的档案或装置去,而分别传送所用的特殊字符则如下所示:
1. 标准输入 (stdin) :代码为 0 ,使用 < 或<< ;
2. 标准输出 (stdout):代码为 1 ,使用 > 或 >> ;
3. 标准错诨输出(stderr):代码为 2 ,使用 2> 或 2>> ;

   1> :以覆盖的方法将『正确的数据』输出到指定的档案或装置上;
   1>>:以累加的方法将『正确的数据』输出到指定的档案或装置上;
   2> :以覆盖的方法将『错误的数据』输出到指定的档案或装置上;
   2>>:以累加的方法将『错误的数据』输出到指定的档案或装置上;

/dev/null 垃圾桶黑洞装置与特殊写法

如果我知道错误讯息会发生,所以要将错误讯息忽略掉而并显示或储存呢? 这个时候黑洞装置 /dev/null 就很重要了!这个 /dev/null 可以吃掉任何导向这个装置的信息

如果我要将正确与错误数据通通写入同一个档案去呢?这个时候就得要使用特殊的写法了! 我们同样用底下的案例来说明:

standard input:< 与 <<

<:将原本需要由键盘输入的数据,改由档案内容取代。

<<:结束的输入字符。

为何要使用命令输出重导向?

   屏幕输出的信息很重要,而且我们需要将他存下来的时候;
   背景执行中的程序,并希望他干扰屏幕正常的输出结果时;
   一些系统的例行命令 (例如写在 /etc/crontab 中的档案) 的执行结果,希望他可以存下来时;
   一些执行命令的可能已知错误讯息时,想以『 2> /dev/null 』将他丢掉时;
   错误讯息与正确讯息需要分别输出时。

命令执行的判断依据: ;, &&, ll

管线命令(pipe)

bash 命令执行时有输出数据出现,如果输出的数据需要经过几道手续后才能得到我们想要的格式,应该如何设定呢?这就牵涉到管线命令,管线命令使用【|】界定符号。

如果我们想知道 /etc 下有多少档案,可以用 ls /etc 来查询,不过因为档案太多,一下把屏幕塞满了,不知道前面输出的内容,此时,可以使用 less 协助:ls -al /etc | less

管线命令只能处理由前面一个指令传来的正确信息,也就是 standard output 的信息,对于 standard error 并没有直接处理的能力。

每个管线后面接的第一个数据必定是指令,而且这个指令必须能够接受 standard input 的数据才行,这样的指令来可以是管线命令,例如less, more, head, tail等。

撷取命令:cut, grep

什么是撷取命令:讲一段数据经过分析后,取出我们想要的。或者经由分析关键词,取出我们想要的哪一行。一般来说,撷取信息通常是针对一行一行来分析的。

cat:将一段信息的某一段切出来,处理信息以行为单位

grep:分析一行信息,若当中有我们需要的信息,就将该行拿出来

排序命令:sort, wc, uniq

sort

uniq

如果我排序完成了,想要将重复的资料仅列出一个显示,可以怎么做呢?

wc

双向重导向:tee

tee 会同时将数据流分送到档案去与屏幕 (screen);而输出到屏幕的,其实就是 stdout ,可以让下个指令继续处理喔!

字符转换命令:tr, col, join, paste, expand

tr 可以用来删除一段讯息当中的文字,或者是进行文字讯息的替换!

col

join

paste

expand

分割命令:split

参数代换:xargs

xargs 可以读入 stdin 的数据,并且以空格符或断行字符作为分辨,将 stdin 的资料分割成为 arguments 。 因为是以空格符作为分割,所以,如果有一些档名或者是其他意义的名词内含有空格符的时候, xargs 可能就会误判了

会使用 xargs 的原因是, 很多指令其实并不支持管线命令,因此我们可以透过 xargs 来提供该指令引用 standard input !举例说:

关于减号 - 的用途

在管线命令当中,常常会使用到前一个指令的 stdout 作为这次的stdin , 某些指令需要用到文件名 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 "-" 来替
代, 举例来说:

上面这个例子是说:『我将 /home 里面的档案给他打包,但打包的数据不是记录到档案,而是传送别stdout; 经过管线后,将 tar -cvf - /home 传送给后面的 tar -xvf - 』。后面的这个 - 则是取用前一个指令的 stdout, 因此,我们就不需要使用 file 了!这是很常见的例子喔!注意注意!

第13章 学习 shell script

什么是 shell script?

shell script 是针对 shell 编写的脚本。shell script 是利用shell的功能编写的一个程序,这个程序使用纯文本文件,将一些shell的语法与指令(含外部指令)写在里面,搭配正则表达式、管线命令和数据流重定向等功能,以达到我们想要的处理目的。

为什么要学习 shell script?

  自动化管理的重要依据

  追踪与管理系统的重要工作

  简单入侵检测功能

  连续指令单一化

  简易的数据处理

  跨平台支持与学习历程较短

第一支 script 的编写与执行

编写 shell script 的注意事项:

  a. 指令的执行是从上而下、从左而右的分析与执行;

  b. 指令、选项与参数间的多个空白都会被忽略掉;

  c. 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样规为空格键;

  d. 如果读取到一个 Enter 符号 (CR) ,就尝试开始执行该行 (或该串) 命令;

  e. 至于如果一行的内容太多,则可以使用『 \[Enter] 』来延伸至下一行;

  f. 『 # 』可做为批注!任何加在 # 后面的资料将全部被规为批注文字而被忽略!

鸟哥的Linux私房菜-第10/11/12/13章(vim程序编辑器、学习bash、正则表达式与文件格式化处理、学习Shell Scripts)的相关教程结束。

《鸟哥的Linux私房菜-第10/11/12/13章(vim程序编辑器、学习bash、正则表达式与文件格式化处理、学习Shell Scripts).doc》

下载本文的Word格式文档,以方便收藏与打印。