.:. 草榴社區 » 技術討論區 » 转载:扫盲 Linux&UNIX 命令行——从“电传打字机”聊到“shell 脚本编程”(下)
--> 本頁主題: 转载:扫盲 Linux&UNIX 命令行——从“电传打字机”聊到“shell 脚本编程”(下) 字體大小 寬屏顯示 只看樓主 最新點評 熱門評論 時間順序
次次換床單


級別:精靈王 ( 12 )
發帖:2982
威望:311 點
金錢:268782424 USD
貢獻:60564 點
註冊:2015-08-10


转载:扫盲 Linux&UNIX 命令行——从“电传打字机”聊到“shell 脚本编程”(下)



接上文https://t66y.com/htm_data/2103/7/4417855.html
★进程的启动与退出

◇进程的【启动】及其【父子关系】

  一般来说,每个“进程”都是由另一个进程启动滴。如果“进程A”创建了“进程B”,则 A 是【父进程】,B 是【子进程】(这个“父子关系”很好理解——因为完全符合直觉)
  有些同学会问,那最早的【第一个】进程是谁启动滴?
  一般来说,第一个进程由【操作系统内核】(kernel)亲自操刀运行起来;而 kernel 又是由“引导扇区”中的“boot loader”加载。

◇进程树

  在 POSIX 系统(Linux & UNIX),所有的进程构成一个【单根树】的层次关系。进程之间的“父子关系”,体现在“进程树”就是树上的【父子节点】。
  你可以使用如下命令,查看当前系统的“进程树”。
pstree[/pre]
 
(“进程树”的效果图。注:为了避免暴露俺的系统信息,特意【不】用自己系统的截图)
◇初始进程

  一般情况下,POSIX 系统的“进程树”的【根节点】就是系统开机之后【第一个】创建的进程,并且其进程编号(PID)通常是 1。这个进程称之为“初始进程”。
  (注:上述这句话并【不够】严密——因为某些 UNIX 衍生系统的“进程树”,位于根节点的进程【不是】“初始化进程”。这种情况与本文的主题没太大关系,俺不打算展开讨论)
  对于“大部分 UNIX 衍生系统”以及“2010年之前的 Linux 发行版”,系统中的“初始进程”名叫 init;
  如今越来越多的 Linux 发行版采用 systemd 来完成系统引导之后的初始化工作。在这些发行版中,“初始进程”名叫 systemd。

  你可以用如下命令显示“进程树”中每个节点的“进程编号”(PID),然后就能看到编号为 1 的“初始进程”。
pstree -p[/pre]
◇进程的三种死法

  关于进程如何死亡,大致有如下三种情况:

  自然死亡
  如果某个进程把它该干的事情都干完了,自然就会退出。
  这种是最常见的情况,也是最优雅的死法。俺习惯称作【自然死亡】。

  自杀
  如果某个进程的工作干到半当中,突然收到某个通知,让它立即退出。
  这时候,进程会赶紧处理一些善后工作,然后自行了断——这就是【自杀】。

  它杀
  比“自杀”更粗暴的方式称之为【它杀】。也就是让“操作系统内核”直接把进程干掉。
  在这种情况下,进程【不会】收到任何通知,因此也【不】可能进行任何善后事宜。

  (注:上述三种死法纯属比喻,以加深大伙儿的印象;不必太较真。十年前俺刚开博客,写过几篇帖子谈“C++ 对象之死”,也用过类似比喻)
  关于“自杀&它杀”的方式,会涉及到【信号】。在下一个章节,俺会单独讨论【进程控制】,并会详细介绍“信号”的机制。

◇“孤儿进程”及其“领养”

  如果某个进程死了(退出了),而它的子进程还【没】死,那么这些子进程就被形象地称之为“孤儿”,然后会被上述提到的【初始进程】“领养”——“初始进程”作为“孤儿进程”的父进程。
  对应到“进程树”——“孤儿进程”会被重新调整到“进程树根节点”的【直接下级】。

 
 ★“进程控制”与“信号”

◇用【Ctrl + C】杀进程

  为了演示这个效果,你可以执行如下命令:
ping 127.0.0.1[/pre]
  如果是 Windows 系统里的 ping 命令,它只会进行4次“乒操作”,然后就自己退出了;
  但对于 POSIX 系统里面的 ping 命令,它会永远运行下去(直到被杀掉)。
  当 ping 在运行的时候,只要你按下 Ctrl + C 这个组合键,就可以立即终止这个 ping 进程。

◇“Ctrl + C”背后的原理——【信号】(signal)

  当你按下了 Ctrl + C 这个组合键,当前正在执行的进程会收到一个叫做【SIGINT】的信号。
  如果进程内部定义了针对该信号的处理函数,那么就会去执行这个函数,完成该函数定义的一些动作。一般而言,该函数会进行一些善后工作,然后进程退出。
  如果进程【没有】定义相应的处理函数,则会执行一个【默认动作】。对于 SIGINT 这个信号而言,默认动作就是“进程退出”。
  上述这2种情况,都属于前面所说的自杀。这2种属于【常规情况】。

  下面再来说【特殊情况】——有时候 Ctrl + C【无法】让进程退出。为啥会这样捏?
  假如说,编写某个进程的程序员,定义了该信号的处理函数,但在这个函数内部,并【没有】执行“进程退出”这个动作。那么当该进程收到 SIGINT 信号之后,自然就【不会】退出。这种情况称之为——信号被该进程【屏蔽】了

◇【谁】发出“Ctrl + C”对应的信号?

  很多人(包括很多玩命令行的老手)都有一个【误解】——他们误以为是 shell 发送了 SIGINT 信号给当前进程。其实不然!
  在上述 ping 的例子中,当 ping 进程在持续运行之时,你的键盘输入是关联到 ping 进程的“标准输入”(stdin)。在这种情况下,shell 根本【无法】获取你的按键信息。
  实际上,是【终端】获取了你的 Ctrl + C 组合键信息,并发送了 SIGINT 信号。因为【终端】处于更底层,它负责承载你所有的输入输出。因此,它当然可以截获用户的某个特殊的组合键(比如:Ctrl + C),并执行某些特定的动作。
  聊到这里,大伙儿会发现——
如果没有正确理解“终端”与“shell”这两者的关系,就会犯很多错误(造成很多误解)。

  有的读者可能会问:“终端”如何知道【当前进程】是哪一个?(能想到这点,通常是比较爱思考滴)
  俺来解答一下:
  当 shell 启动了某个进程,它当然可以拿到这个进程的编号(pid),于是 shell 会调用某个系统 API(比如 tcsetpgrp)把“进程编号”与 shell 所属的“终端”关联起来。
  当“终端”需要发送 SIGINT 信号时,再调用另一个系统 API(比如 tcgetpgrp),就可以知道当前进程的编号。

◇对比杀进程的几个信号:SIGINT、SIGTERM、SIGQUIT、SIGKILL

  SIGINT
  在大部分 POSIX 系统的各种终端上,Ctrl + C 组合键触发的就是这个信号。
  通常情况下,进程收到这个信号后,做完相关的善后工作,就自行了断(自杀)。

  SIGTERM
  这个信号基本类似于 SIGINT。
  它是 kill & killall 这两个命令【默认】使用的信号。
  也就是说,当你用这俩命令杀进程,并且【没有】指定信号类型,那么 kill 或 killall 用的就是这个 SIGTERM 信号。

  SIGQUIT
  这个信号类似于前两个(SIGINT & SIGINT),差别在于——进程在退出前会执行“core dump”操作。
  一般而言,只有程序员才会去关心“core dump”这个玩意儿,所以这里就不细聊了。

  SIGKILL
  在杀进程的几个信号中,这个信号是是最牛逼的(也是最粗暴的)。
  前面三个信号都是【可屏蔽】滴,而这个信号是【不可屏蔽】滴。
  当某个进程收到了【SIGKILL】信号,该进程自己【完全没有】处理信号的机会,而是由操作系统内核直接把这个进程干掉。
  此种行为可以形象地称之为“它杀”。
  当你用下列这些命令杀进程,本质上就是在发送这个信号进行【它杀】。【SIGKILL】这个信号的编号是 9,下列这些命令中的 -9 参数就是这么来滴。
kill -9 进程号kill -KILL 进程号killall -9 进程名称killall -KILL 进程名称killall -SIGKILL 进程名称[/pre]
  为了方便对照上述这4种,俺放一个表格如下:
信号名称编号能否屏蔽默认动作俗称
SIGINT2YES进程自己退出自杀
SIGTERM15YES进程自己退出自杀
SIGQUIT3YES执行 core dump
进程自己退出
自杀
SIGKILL9NO进程被内核干掉它杀

◇【它杀】的危险性与副作用

  请注意:【它杀】是一种比较危险的做法,可能导致一些【副作用】。只有当你用其它各种方式都无法干掉某个进程,才考虑用这招。
  有读者在评论区问到了“它杀的副作用”,俺简单解释一下:
  一方面,当操作系统用这种方式杀掉某个进程,虽然可以把很多内存相关的资源释放掉,但【内存之外】的资源,内核就管不了啦;另一方面,由于进程遭遇“它杀”,无法完成某些善后工作。
  基于上述两点,就【有可能】会产生副作用。另外,“副作用的严重程度”取决于不同类型的软件。无法一概而论。

  举例1:
  某个进程正在保存文件。这时候遭遇“它杀”可能会导致文件损坏。
  (注:虽然某些操作系统能做到“写操作的原子性”,但数据存储可能会涉及多个写操作。当进程在作【多个】关键性写操作时,遭遇它杀。可能导致数据文件【逻辑上】的损坏)

  举例2:
  还有更复杂的情况,比如涉及跨主机的网络通讯。某个进程可能向【远程】的某个网络服务分配了某个远程的资源,当进程“自然死亡 or 自杀”,它会在“善后工作”释放这个资源;而如果死于内核的“它杀”,这个远程的资源就【没】释放。

◇kill VS killall

  这两个的差别在于——前者用“进程号”,后者用”进程名“(也就是可执行文件名)。
  对于新手而言,
如果用 kill 命令,你需要先用 ps 命令打印出当前进程清单,然后找到你要杀的进程的编号;而如果要用 killall 命令,就比较省事(比较傻瓜化)。但万一碰到有多个【同名】进程在运行,而你只想干掉其中一个,那么就得老老实实用 kill 了。

◇进程退出码

  任何一个进程退出的时候,都对应某个【整数类型】的“退出码”。
  按照 POSIX 系统(UNIX & Linux)的传统惯例——
当“退出码”为【零】,表示“成功 or 正常状态”;
当“退出码”【非零】,表示“失败 or 异常状态”。

◇暂停进程

  刚才聊“杀进程”的时候提到了“自杀 VS 它杀”。前者比较“温柔”;而后者比较“粗暴”。
  对于暂停进程,也有“温柔 & 野蛮”两种玩法。而且也是用 kill 命令发信号。

  【温柔】式暂停(SIGTSTP)
kill -TSTP 进程编号[/pre]  这个【SIGTSTP】信号类似前面提及的【SIGINT】——
1. 两者默认都绑定到组合键(【SIGINT】默认绑定到组合键【Ctrl + C】;【SIGTSTP】默认绑定到组合键【Ctrl + Z】)
2. 这两个快捷键都是由【终端】截获,并发出相应的信号(具体原理参见本章节的某个小节)
3. 两者都是【可】屏蔽的信号。也就是说,如果某个进程屏蔽了【SIGTSTP】信号,你就【无法】用该方式暂停它。这时候你就得改用【粗暴】的方式(如下)。

  【粗暴】式暂停(SIGSTOP)
kill -STOP 进程编号[/pre]  这个【SIGSTOP】信号与前面提及的【SIGKILL】有某种相同之处——这两个信号都属于【不可屏蔽】的信号。也就是说,收到【SIGSTOP】信号的进程【无法】抗拒被暂停(suspend)的命运。

  与“杀进程”的风格类似——当你想要暂停某进程,应该先尝试“温柔”的方法,搞不定再用“粗暴”的方法(套用咱们天朝的老话叫“先礼后兵”)。

◇恢复进程

  当你想要重新恢复(resume)被暂停的进程,就用如下命令(该命令发送信号【SIGCONT】)
kill -CONT 进程编号[/pre]
◇引申阅读

  除了前面几个小节提到的信号,POSIX 系统还支持其它一些信号,具体参见维基百科的“这个页面”。

 
 ★作业控制(job)

  聊完了“进程控制”,再来聊“作业控制”。
  (注:这里所说的“作业”是从洋文 job 翻译过来滴)

◇啥是“作业”?

  “作业”是 shell 相关的术语,用来表示【进程组】的概念(每个作业就是一组进程)。
  比如说,当你用“管道符”把若干命令串起来执行,这几个命令对应的进程就被视作【一组】。
  (注:“管道符”的用法,后面某个章节会介绍)

◇同步执行(前台执行) VS 异步执行(后台执行)

  大部分情况下,你在 shell 中执行的命令都是“同步执行”(或者叫“前台执行”)。对于这种方式,只有当命令运行完毕,你才会重新看到 shell 的“命令行提示符”。
  如果你以“异步执行”的方式启动某个外部命令,在这个命令还没有执行完的时候,你就可以重新看到“命令行提示符”。

  请注意:
  对于【短】寿命的外部命令(耗时很短的外部命令),“同步/异步”两种方式其实【没】啥区别。比如 ls 命令通常很快就执行完毕,你就感觉不到上述两种方式的差异。
  只有当你执行了某个【长】寿命的外部命令(其执行时间至少达到若干秒),上述这两种方式才会体现出差别。

  到目前为止,本文之前聊的命令执行方式,都属于“同步执行”;如果想用【异步】,需要在整个命令的最末尾追加一个半角的 & 符号。

  【同步】方式举例
  下列命令以【同步】的方式启动火狐浏览器,只有当你关闭了火狐,才会重新看到 shell 的命令行提示符。
firefox[/pre]
  【异步】方式举例
  下列命令以【异步】的方式启动火狐浏览器。你刚敲完回车,就会重新看到 shell 的“命令行提示符”(此时火狐依然在运行)
firefox &[/pre]
  以“同步”方式启动的进程,称作“【前台】进程”;反之,以“异步”方式启动的进程,称作“【后台】进程”。

◇“前台”切换到“后台”

  假设当前的 shell 正在执行某个长寿命的【前台】进程,你可以按【Ctrl + Z】,就可以让该进程变为【后台】进程——此时你立即可以看到“命令提示符”。
  只要你不是太健忘,应该记得前一个章节有提到过【Ctrl + Z】这个组合键——它用来实现”【温柔】式暂停“,其原理是:向目标进程发送【SIGTSTP】信号。

◇“后台”切换到“前台”

  假设当前 shell 正在执行某个后台进程。由于该进程在【后台】执行,此时有“命令提示符”,然后你在 shell 中执行 fg 命令,就可以把该后台进程切换到【前台】。

  某些爱思考的同学会问了——如果同时启动了【多个】“后台进程”,fg 命令会切换哪一个捏?
  在这种情况下,fg 命令切换的是【最后启动】的那个。

  如果你有 N 个“后台进程”,你想把其中的某个切换为“前台进程”,这时候就需要用到 jobs 命令。该命令与乔布斯同名 :)
  举例:
  假设俺同时启动了 vim 与 emacs 作为后台进程,先用 jobs 命令列出所有的后台进程。假设该命令的输出是如下这个样子。
$ jobs[1]  running    vim[2]  running    emacs[/pre]  在上述的终端窗口,中括号里面的数字称作“job id”。你可以用 fg 命令搭配“job id”,把某个后台进程切换到前台。
  (在本例中)如果你想切换 emacs 到前台,就运行 fg %2,如果想切换 vim 就运行 fg %1(以此类推)

◇引申阅读

  想进一步了解“作业控制”,可以参考维基百科(这个链接)。

 
 ★环境变量(environment variable)

◇“环境变量”是啥?

  所谓的“环境变量”,你可以通俗理解为某种【名值对】——每个“环境变量”都有自己的【名称】和【值】。并且名称必须是【唯一】滴。

◇如何添加并修改“环境变量”?

  在 bash(或兼容 bash 的其它 shell),你可以用 export 设置环境变量。比如下面这个命令行设置了一个“环境变量”,其名称是 abc,其值是 xyz
export abc=xyz[/pre]
  假如你要设置的【值】包含空格,记得用双引号引用该值(示例如下)。
export abc="program think"[/pre]
  由于“环境变量”的名称具有【唯一性】,当你设置【同名】的“环境变量”就等同于对它的【修改】。

◇如何查看“环境变量”?

  设置完之后,你可以用 env 命令查看。该命令会列出【当前 shell】中的【全部】“环境变量”。

◇“环境变量”的【可见性】和【可继承性】

  某个进程设置的“环境变量”,其【可见性】仅限于该进程及其子进程(也就是“进程树”中,该进程所在的那个枝节)。
  基于上述的【可见性】原则,你在某个 shell 中设置的“环境变量”,只在“该 shell 进程本身”,以及通过该 shell 进程启动的“其它子进程”,才能看到。

  另外,如果系统关机,所有进程都会退出,那么你采用上一个小节(export 方式)设置的“环境变量”也就随之消失了。
  为了让某个“环境变量”永久生效,需要把相应的 export 命令添加到该 shell 的初始化配置文件中。对于 bash 而言,也就是 ~/.bashrc 或者 ~/.profile
  估计有些同学会问:上述这两个初始化配置文件,有啥差别捏?
  俺如果有空,会单独写一篇关于 bash 的定制教程,到时候再聊这个话题。

◇“环境变量”有啥用?

  通俗地说,“环境变量”是某种比较简单的“IPC 机制”(进程通讯机制),可以让两个进程共享某个简单的文本信息。
  举例:
  很多知名的软件(比如:curl、emacs)都支持“以环境变量设置代理”。
  如果你按照它的约定,在 shell 中设置了约定名称和格式的“环境变量”,然后在【同一个】shell 中启动这个软件,(由于环境变量的【可继承性】)该软件就会看到这个“环境变量”,并根据“环境变量”包含的信息,设置代理。

 
 ★“标准流”(standard stream)与“重定向”(redirection)

◇进程的3个“标准流”

  在 POSIX 系统(Linux & UNIX)中,每个进程都内置了三个“标准流”(standard stream),分别称作:“标准输入流”(stdin),“标准输出流”(stdout),“标准错误输出流”(stderr)。
  当进程启动后,在默认情况下,stdin 对接到终端的【输入】;stdout & stderr 对接到终端的【输出】。示意图如下:

 
(三个【标准流】的示意图)
  如果你是程序员,俺补充一下:
  当你在程序中打开某个文件,会得到一个“文件描述符”(洋文叫“file descriptor”,简称 fd)。fd 本身是个整数,程序员可以通过 fd 对该文件进行读写。
  而进程的三个【标准流】,就相当于是三个特殊的 fd。当进程启动时,操作系统就已经把这三个 fd 准备好了。
  由于这三个玩意儿是预先备好滴,所以它们的数值分别是:0、1、2(参见上图中 # 后面的数字)。

◇演示“标准流”的实际效果

  在本文前面的某个章节,俺已经用 gif 动画演示了终端的“行模式”。
  动画中的 cat 命令同样可以用来演示“标准输入输出”。俺把那个动画再贴一次。

 
(动画:“标准输入输出”的效果)
  请注意,第1行 test 是针对 cat 进程的【输入】,对应于【stdin】(你之所以能看到这行,是因为前面所说的【终端回显】)
  第2行 test 是 cat 进程拿到输入文本之后的原样输出,对应于【stdout】。

◇“标准流”的【重定向

  所谓的【重定向】大体上分两种:

  1. 【输入流】重定向
  把某个文件重定向为 stdin;此时进程通过 stdin 读取的是该文件的内容。
  这种玩法使用小于号(<)

  2. 【输出流】重定向
  把 stdout 重定向到某个文件;此时进程写入 stdout 的内容会【覆盖 or 追加】到这个文件。
  这种玩法使用【单个】大于号(>)或【两个】大于号(>>)。前者用于【覆盖】文件内容,后者用于【追加】文件内容。

  另外,有时候你会看到 2>&1 这种写法。它表示:把 stderr 合并到 stdout。
  (注:前面俺提到过——stdout 是“数值为 1 的文件描述符”;stderr 是“数值为 2 的文件描述符”)

◇【重定向】举例

  cat 的例子
  下面这个命令把某个文件重定向到 cat 的 stdin。
cat < 文件名[/pre]
  很多菜鸟容易把上面的命令与下面的命令搞混淆。
  请注意:上面的命令用的是【输入重定向】,而下面的命令用的是【命令行参数】。
cat 文件名[/pre]
  cat 命令还可以起到类似“文件复制”的效果。
  比如你已经有个 文件1,用下面这种玩法,会创建出一个内容完全相同的 文件2。
cat < 文件1 > 文件2[/pre]  某些同学可能会问了:既然能这么玩,为啥还需要用 cp 命令进行文件复制捏?
  原因在于:cat 的玩法,只保证内容一样,其它的不管;而 cp 除了复制文件内容,还会确保“目标文件”与“源文件”具有相同的属性(比如 mode)。

  更多的例子
  在之前那篇《扫盲 netcat(网猫)的 N 种用法——从“网络诊断”到“系统入侵”》,里面介绍了十多种 nc 的玩法。很多都用到了【重定向】。

 
 ★匿名管道(anonymous pipe)

◇“匿名管道”的【原理】

  在大部分 shell 中,使用竖线符号(|)来表示【管道符】。用它来创建一个【匿名管道】,使得前一个命令(进程)的“标准输出”关联到后一个命令(进程)的“标准输入”。

◇举例

  俺曾经在“这篇博文”中介绍过——如何用 netstat 查看当前系统的监听端口。
  对于 Windows 系统,可以用如下命令:
netstat -an | find "LISTEN"[/pre]  对于 POSIX 系统,可以用如下命令:
netstat -an | grep "LISTEN"[/pre]
  在上述两个例子中,都用到了【管道符】。因为 netstat -an 这个命令的输出可能会很多,先把它的输出通过【匿名管道】丢给某个专门负责过滤的命令(比如:POSIX 的 grep 或 Windows 的find)。当这个过滤命令拿到 netstat 的输出内容,再根据你在命令行参数中指定的【关键字】(也就是上述例子中的 LISTEN),过滤出包含【关键字】的那些【行】。
  最终,你看到的是“过滤命令”(grep 或 find)的输出。

◇【串联的】匿名管道(chained pipeline)

  前面的例子,可以用来列出当前系统中所有的监听端口。
  现在,假设你运行了 Tor Browser,然后想看看它到底有没有开启 9150 这个监听端口,那么你就可以在上述命令中进行【二次过滤】(具体命令大致如下)。这就是所谓的【串联】。
netstat -an | grep "LISTEN" | grep "9150"[/pre]
◇“匿名管道”与“作业”(进程组)

  用“匿名管道”串起来的多个进程,构成一个“作业”(这点前面提到了)。
  你可以尝试执行某个长寿命的,带管道符的命令行,然后用 Ctrl + Z 切到后台,再执行 jobs 看一下,就能看出——该命令行对应的【多个】进程属于同一个 job。

 
 ★批处理(batch)

◇啥是“批处理”?

  通俗地说就是:同时执行多个命令。
  为了支持“批处理”,shell 需要提供若干语法规则。而且不同类型的 shell,用来搞“批处理”的语法规则也存在差异。
  在本章节中,俺以 bash 来举例。

◇【无】条件的“批处理”

  如果你把多个命令写在同一行,并且命令之间用半角分号隔开,这种玩法就属于【无条件】的批处理执行。
  举例:
  假设当前目录下有一个 abc.txt 文件,然后要在当前目录下创建一个名为 xxx 的子目录,并把 abc.txt 移动到这个新创建的子目录中。你可以用如下方式搞定(只用【一行】命令)
mkdir ./xxx/; mv abc.txt ./xxx/[/pre]
  为啥这种方式叫做“【无条件】批处理”捏?因为不管前一个“子命令”是否成功,都会继续执行下一个“子命令”。

  请注意:
  虽然俺上述举例只使用了两个“子命令”,但实际上这种玩法可以把 N 个“子命令”串起来。

◇【有】条件的“批处理”

  与“无条件”相对应的,当然是“有条件”啦。
  这种玩法的意思是——后一个“子命令”是否执行,取决于【前一个】“子命令”的结果(成功 or 失败)。
  (注:如何界定“成功/失败”,请参见前面某个章节聊到的【进程退出码】)
  【有】条件的批处理,常见的方式有两种,分别是【逻辑与】、【逻辑或】。

  逻辑与(语法:&&)
  只要前面的某个“子命令”【失败】了,就【不再】执行后续的“子命令”。
  举例:
  还是拿前一个小节的例子。如下方式使用了“逻辑与”。如果创建子目录失败,就【不再】执行“移动文件”的操作
mkdir ./xxx/ && mv abc.txt ./xxx/[/pre]
  逻辑或(语法:||)
  只要前面的某个“子命令”【成功】了,就【不再】执行后续的“子命令”。
  举例:
  把上述例子进一步扩充,变为如下:
mkdir ./xxx/ && mv abc.txt ./xxx/ || echo "FAILED!!!"[/pre]
  这个有点复杂,俺稍微解释一下:
  你把前面两句看作一个【整体】。其执行的逻辑参见前面所说的“逻辑与”。然后这个“整体”与后面的那句 echo 再组合成【逻辑或】的关系。
  也就是说,如果前面的“整体”成功了,那么就【不】执行 echo(【不】打印错误信息);反之,如果前面的“整体”失败了,就会打印错误信息。


 ★shell 脚本

  虽然前一个章节拿 bash 来举例。但其实有很多其它类型的 shell 都支持类似的“批处理”机制。
  只要某个 shell 支持刚才所说的【有条件批处理】的机制,它就已经很接近【编程语言】了。
  于是很自然地,那些 shell 的作者就会把 shell 逐步发展成某种【脚本语言】的解释器。然后就有了如今的“shell script”(shell 脚本)和“shell 编程”。
  由于“shell 编程”这个话题比较大。哪怕俺只聊 bash 这一类 shell 的编程,也足够写上几万字的博文。考虑到本文已经很长了,这个话题就不再展开。
  对此感兴趣的同学,可以参考俺分享的电子书。具体参见电子书清单的如下几本(这几本都位于【IT类 / 操作系统 / 使用教程】分类目录下)
Shell 脚本学习指南》(Classic Shell Scripting)
Linux 与 UNIX Shell 编程指南》(Linux and UNIX Shell Programming)
高级 Bash 脚本编程指南》(Advanced Bash-Scripting Guide)
  上述这几本,都属于俺在《如何【系统性学习】——从“媒介形态”聊到“DIKW 模型”》中提到的【入门性读物】。最后一本书的名称中虽然有“高级”字样,不过别怕——其内容的5个部分,有4部分都是在讲基础的东西,只有最后一部分才稍微有一点点深度。


 ★结尾

  由于这篇涉及的内容比较杂,跨度也比较大。可能会有一些俺没覆盖到的地方。欢迎在博客留言中补充。
  如果你发现本文的错误之处,也欢迎批评指正 :)


俺博客上,和本文相关的帖子(需翻墙)
扫盲 Linux:新手如何搞定 Linux 操作系统
扫盲 Linux:如何选择发行版
扫盲 netcat(网猫)的 N 种用法——从“网络诊断”到“系统入侵”
多台电脑如何【共享】翻墙通道——兼谈【端口转发】的几种方法
如何让【不支持】代理的网络软件,通过代理进行联网(不同平台的 N 种方法)
扫盲操作系统虚拟机》(系列)
如何【系统性学习】——从“媒介形态”聊到“DIKW 模型”版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者[url=mailto:program.think@gmail.com]编程随想[/url]和本文原始地址:
https://program-think.blogspot.com/2019/11/POSIX-TUI-from-TTY-to-Shell-Programming.html

赞(3)
TOP Posted:2021-03-30 11:03 樓主 引用 | 發表評論
cl过客


級別:精靈王 ( 12 )
發帖:3659
威望:307 點
金錢:200042 USD
貢獻:42300 點
註冊:2015-03-06


1024
TOP Posted:2021-03-30 11:05 #1樓 引用 | 點評
蜀道难


級別:俠客 ( 9 )
發帖:1087
威望:110 點
金錢:4 USD
貢獻:0 點
註冊:2015-03-31

好东西,感谢分享
TOP Posted:2021-03-30 11:12 #2樓 引用 | 點評
GunSmith


級別:騎士 ( 10 )
發帖:3549
威望:357 點
金錢:42 USD
貢獻:0 點
註冊:2016-05-19

不明所以,但支持技术发帖
TOP Posted:2021-03-30 11:54 #3樓 引用 | 點評
饮屎作乐


級別:光明使者 ( 14 )
發帖:3368
威望:435 點
金錢:2145483655 USD
貢獻:1951151 點
註冊:2013-08-09

没有基础不行
TOP Posted:2021-03-30 11:58 #4樓 引用 | 點評
火之歌


級別:禁止發言 ( 8 )
發帖:13600
威望:1356 點
金錢:2753 USD
貢獻:1 點
註冊:2019-05-23

的确如此
TOP Posted:2021-03-30 13:25 #5樓 引用 | 點評
漫漫人生


級別:聖騎士 ( 11 )
發帖:7853
威望:789 點
金錢:52 USD
貢獻:544 點
註冊:2017-04-06

感谢分享
TOP Posted:2021-03-30 13:33 #6樓 引用 | 點評
ryurik168


級別:聖騎士 ( 11 )
發帖:7005
威望:716 點
金錢:619 USD
貢獻:66 點
註冊:2011-11-01

感谢分享
TOP Posted:2021-03-30 14:15 #7樓 引用 | 點評
Guu


級別:騎士 ( 10 )
發帖:4213
威望:460 點
金錢:0 USD
貢獻:0 點
註冊:2020-08-31

感谢分享
TOP Posted:2021-03-30 15:36 #8樓 引用 | 點評
mscxckc


級別:騎士 ( 10 )
發帖:3035
威望:487 點
金錢:5674 USD
貢獻:0 點
註冊:2021-01-27

谢谢分享
TOP Posted:2021-03-30 17:45 #9樓 引用 | 點評
风吹蛋蛋热


級別:聖騎士 ( 11 )
發帖:3539
威望:354 點
金錢:1505085 USD
貢獻:22444 點
註冊:2020-01-31

论坛有你更精彩
TOP Posted:2021-03-31 01:11 #10樓 引用 | 點評
大鸟转转转


級別:俠客 ( 9 )
發帖:994
威望:100 點
金錢:1 USD
貢獻:0 點
註冊:2021-01-03


多谢分享
TOP Posted:2021-03-31 05:01 #11樓 引用 | 點評
Jasper_Z


級別:俠客 ( 9 )
發帖:2954
威望:286 點
金錢:551 USD
貢獻:0 點
註冊:2019-08-25

感谢分享
TOP Posted:2021-03-31 06:35 #12樓 引用 | 點評
fack666


級別:騎士 ( 10 )
發帖:4632
威望:464 點
金錢:2637 USD
貢獻:0 點
註冊:2020-11-11

谢谢坛友分享
TOP Posted:2021-03-31 07:16 #13樓 引用 | 點評
桑渺


級別:俠客 ( 9 )
發帖:2370
威望:238 點
金錢:296727 USD
貢獻:0 點
註冊:2018-12-20

我在黄网学IT
TOP Posted:2021-03-31 07:29 #14樓 引用 | 點評
诺贝尔没得奖


級別:俠客 ( 9 )
發帖:1535
威望:154 點
金錢:7576 USD
貢獻:0 點
註冊:2019-02-16

内容精彩
TOP Posted:2021-03-31 07:58 #15樓 引用 | 點評
感谢姐姐


級別:俠客 ( 9 )
發帖:1604
威望:152 點
金錢:51327186 USD
貢獻:0 點
註冊:2015-05-28

感谢分享
TOP Posted:2021-03-31 08:12 #16樓 引用 | 點評
佛性常清净


級別:俠客 ( 9 )
發帖:883
威望:112 點
金錢:6 USD
貢獻:0 點
註冊:2020-10-10


谢谢分享
TOP Posted:2021-03-31 08:14 #17樓 引用 | 點評
以防万一


級別:俠客 ( 9 )
發帖:1126
威望:113 點
金錢:1126 USD
貢獻:1 點
註冊:2018-05-21

内容精彩
TOP Posted:2021-03-31 08:50 #18樓 引用 | 點評
佛魔一念间


級別:精靈王 ( 12 )
發帖:13596
威望:1483 點
金錢:15123 USD
貢獻:80 點
註冊:2020-04-24

感谢分享
TOP Posted:2021-03-31 09:13 #19樓 引用 | 點評
伽利略略略


級別:騎士 ( 10 )
發帖:3612
威望:352 點
金錢:1420494 USD
貢獻:5000 點
註冊:2020-03-25

支持分享
TOP Posted:2021-03-31 09:19 #20樓 引用 | 點評
ztofight


級別:新手上路 ( 8 )
發帖:47
威望:5 點
金錢:47 USD
貢獻:0 點
註冊:2020-12-18

楼主这个贴子真的太及时了,这段时间正准备学习一下linux,一拿起书就犯困,这下好了,可以认真的学习起来了。拜谢.
TOP Posted:2021-03-31 10:01 #21樓 引用 | 點評
feiyafei


級別:聖騎士 ( 11 )
發帖:5474
威望:555 點
金錢:86 USD
貢獻:3188 點
註冊:2021-03-16

专业分享
------------------------
TOP Posted:2021-03-31 10:21 #22樓 引用 | 點評
人出鬼没


級別:聖騎士 ( 11 )
發帖:1016
威望:102 點
金錢:6800480 USD
貢獻:39973 點
註冊:2014-02-04


谢谢分享
TOP Posted:2021-03-31 11:30 #23樓 引用 | 點評
龙狼蝶影


級別:聖騎士 ( 11 )
發帖:7477
威望:752 點
金錢:16750961 USD
貢獻:0 點
註冊:2015-05-12

感谢分享
TOP Posted:2021-03-31 15:44 #24樓 引用 | 點評

.:. 草榴社區 -> 技術討論區

快速回帖 頂端
內容
HTML 代碼不可用

使用簽名
Wind Code自動轉換

按 Ctrl+Enter 直接提交