您现在的位置是:网站首页> 编程资料编程资料

Linux系统中bash shell编程的10个基础问题讲解_linux shell_

2023-05-26 471人已围观

简介 Linux系统中bash shell编程的10个基础问题讲解_linux shell_

第1问:为何叫做shell?
在介绍 shell 是什么东西之前,不妨让我们重新审视使用者与电脑的关系。我们知道电脑的运作不能离开硬件,但使用者却无法直接对硬件作驱动,硬件的驱动只能透过一个称为“操作系统(Operating System)”的软件来控管,事实上,我们每天所谈的linux,严格来说只是一个操作系统,我们称之为“核心(kernel)”。然而,从使用者的角度来说,使用者也没办法直接操作kernel,而是透过kernel的“外壳”程序,也就是所谓的shell,来与kernel沟通。
这也正是kernel跟shell的形像命名关系。

从技术角度来说,shell是一个使用者与系统的互动界面(interface),主要是让使用者透过命令行(command line)来使用系统以完成工作。因此,shell的最简单的定义就是---命令解释器(Command Interpreter):

  • 将使用者的命令翻译给核心处理,
  • 同时,将核心处理结果翻译给使用者。

每次当我们完成系统登入(log in),我们就取得一个互动模式的shell,也称为login shell或primary shell。若从行程(process)角度来说,我们在shell所下达的命令,均是shell所产生的子行程。这现像,我们暂可称之为fork。如果是执行脚本(shell script)的话,脚本中的命令则是由另外一个非互动模式的子shell(sub shell)来执行的。也就是primary shell产生sub shell的行程,sub shell再产生script中所有命令的行程。(关于行程,我们日后有机会再补充。)

这里,我们必须知道:kernel与shell是不同的两套软件,而且都是可以被替换的:

  • 不同的操作系统使用不同的kernel,
  • 而在同一个kernel之上,也可使用不同的shell。

在linux的预设系统中,通常都可以找到好几种不同的shell,且通常会被列于如下档案里:

/etc/shells
不同的shell有着不同的功能,且也彼此各异、或说“大同小异”。常见的shell主要分为两大主流:
sh:

  • burne shell(sh)
  • burne again shell(bash)

csh:

  • c shell(csh)
  • tc shell(tcsh)
  • korn shell(ksh)

大部份的Linux系统的预设shell都是bash,其原因大致如下两点:

  • 自由软件
  • 功能强大

bash是gnu project最成功的产品之一,自推出以来深受广大Unix用户喜爱,且也逐渐成为不少组织的系统标准。

第2问:shell prompt(PS1)与 Carriage Return(CR)的关系?
当你成功登录进一个文字界面之后,大部份情形下,你会在荧幕上看到一个不断闪烁的方块或底线(视不同版本而别),我们称之为游标(cursor)。游标的作用就是告诉你接下来你从键盘输入的按键所插入的位置,且每输入一键游标便向右边移动一个格子,若连续输入太多的话,则自动接在下一行输入。假如你刚完成登录还没输入任何按键之前,你所看到的游标所在位置的同一行的左边部份,我们称之为提示符号(prompt)。提示符号的格式或因不同系统版本而各有不同,在Linux上,只需留意最接近游标的一个可见的提示符号,通常是如下两者之一:

  • $:给一般使用者帐号使用
  • #:给root(管理员)帐号使用

事实上,shell prompt的意思很简单:是shell告诉使用者:您现在可以输入命令行了。我们可以说,使用者只有在得到shell prompt才能打命令行,而cursor是指示键盘在命令行所输入的位置,使用者每输入一个键,cursor就往后移动一格,直到碰到命令行读进CR(Carriage Return,由Enter键产生)字符为止。CR的意思也很简单:是使用者告诉shell:老兄你可以执行我的命令了。

严格来说:所谓的命令行,就是在shell prompt与CR字符之间所输入的文字。(思考:为何我们这里坚持使用CR字符而不说Enter键呢?答案在后面的学习中揭晓。)不同的命令可接受的命令行格式或有不同,一般情况下,一个标准的命令行格式为如下所列:

command-name options argument
若从技术细节来看,shell会依据IFS(Internal Field Seperator)将command line所输入的文字给拆解为“字段”(word)。然后再针对特殊字符(meta)先作处理,最后再重组整行command line。(注意:请务必理解上两句话的意思,我们日后的学习中会常回到这里思考。)

其中的IFS是shell预设使用的字段分隔符号,可以由一个及多个如下按键组成:

  • 空白键(White Space)
  • 表格键(Tab)
  • 回车键(Enter)

系统可接受的命令名称(command-name)可以从如下途径获得:

明确路径所指定的外部命令

  • 命令别名(alias)
  • 自定功能(function)
  • shell内置命令(built-in)
  • $PATH之下的外部命令

每一个命令行均必需含用命令名称,这是不能缺少的。

第3问:别人echo、你也echo,是问echo知多少?
承接上一章所介绍的command line,这里我们用echo这个命令加以进一步说明。温习---标准的command line包含三个部件:

command_name option argument
echo是一个非常简单、直接的Linux命令:将argument送出至标准输出(STDOUT),通常就是在显示器(monitor)上输出。(注:stdout我们日后有机会再解说)。为了更好理解,不如先让我们先跑一下echo命令好了:

$ echo
你会发现只有一个空白行,然后又回到shell prompt上了。这是因为echo在预设上,在显示完argument之后,还会送出一个换行符号(new-line charactor)。但是上面的command并没任何的argument,那结果就只剩一个换行符号了…

若你要取消这个换行符号,可利用echo的-n option:

$ echo -n
不妨让我们回到command line的概念上来讨论上例的echo命令好了:command line只有command_name(echo)及option(-n),并没有任何argument。

要想看看echo的argument,那还不简单﹗接下来,你可试试如下的输入:

 $ echo first line first line $ echo -n first line first line $ 

于上两个echo命令中,你会发现argument的部份显示在你的荧幕,而换行符号则视-n option的有无而别。
很明显的,第二个echo由于换行符号被取消了,接下来的shell prompt就接在输出结果同一行了…^_^

事实上,echo除了-n options之外,常用选项还有:

  • -e:启用反斜线控制字符的转换(参考下表)
  • -E:关闭反斜线控制字符的转换(预设如此)
  • -n:取消行末之换行符号(与-e选项下的\c字符同意)

关于echo命令所支持的反斜线控制字符如下表:

  • \a:ALERT / BELL(从系统喇叭送出铃声)
  • \b:BACKSPACE,也就是向左退格键
  • \c:取消行末之换行符号
  • \E:ESCAPE,跳脱键
  • \f:FORMFEED,分页字符
  • \n:NEWLINE,换行字符
  • \r:RETURN,回车键
  • \t:TAB,表格跳位键
  • \v:VERTICAL TAB,垂直表格跳位键
  • \n:ASCII八进位编码(以x开首为十六进位)
  • \\:反斜线本身

(表格数据来自O'Reilly出版社之Learning the Bash Shell,2nd Ed.)

或许,我们可以透过实例来了解echo的选项及控制字符:
例一:

 $ echo -e "a\tb\tc\nd\te\tf" a b c d e f 

上例运用\t来区隔abc还有def,及用\n将def换至下一行。

例二:

 $ echo -e "\141\011\142\011\143\012\144\011\145\011\146" a b c d e f 

与例一的结果一样,只是使用ASCII八进位编码。

例三:

 $ echo -e "\x61\x09\x62\x09\x63\x0a\x64\x09\x65\x09\x66" a b c d e f 

与例二差不多,只是这次换用ASCII十六进位编码。

例四:

 $ echo -ne "a\tb\tc\nd\te\bf\a" a b c d f $ 

因为e字母后面是退格键(\b),因此输出结果就没有e了。在结束时听到一声铃向,那是\a的杰作﹗
由于同时使用了-n选项,因此shell prompt紧接在第二行之后。若你不用-n的话,那你在\a后再加个\c,也是同样的效果。

事实上,在日后的shell操作及shell script设计上,echo命令是最常被使用的命令之一。
比方说,用echo来检查变量值:

 $ A=B $ echo $A B $ echo $? 0 

(注:关于变量概念,我们留到下两章才跟大家说明。)
好了,更多的关于command line的格式,以及echo命令的选项,就请您自行多加练习、运用了…

第4问:“”(双引号)与''(单引号)差在哪?
还是回到我们的command line来吧…

经过前面两章的学习,应该很清楚当你在shell prompt后面敲打键盘、直到按下Enter的时候,
你输入的文字就是command line了,然后shell才会以行程的方式执行你所交给它的命令。但是,你又可知道:你在command line输入的每一个文字,对shell来说,是有类别之分的呢?

简单而言(我不敢说这是精确的定议,注一),command line的每一个charactor,分为如下两种:

  • literal:也就是普通纯文字,对shell来说没特殊功能。
  • meta:对shell来说,具有特定功能的特殊保留字元。(注一:关于bash shell在处理command line时的顺序说明,请参考O'Reilly出版社之Learning the Bash Shell,2nd Edition,第177 - 180页的说明,尤其是178页的流程图Figure 7-1…)

Literal没甚么好谈的,凡举abcd、123456这些“文字”都是literal…(easy?)。但meta却常使我们困惑…..(confused?)事实上,前两章我们在command line中已碰到两个机乎每次都会碰到的meta:

  • IFS:由三者之一组成(我们常用space)。
  • CR:由产生。

IFS是用来拆解command line的每一个词(word)用的,因为shell command line是按词来处理的。而CR则是用来结束command line用的,这也是为何我们敲命令就会跑的原因。除了IFS与CR,常用的meta还有:

  • = : 设定变量。
  • $ : 作变量或运算替换(请不要与shell prompt搞混了)。
  • > : 重导向stdout。
  • < : 重导向stdin。
  • | : 命令管线。
  • & : 重导向file descriptor,或将命令置于背境执行。
  • () : 将其内的命令置于nested subshell执行,或用于运算或命令替换。
  • {} : 将其内的命令置于non-named function中执行,或用在变量替换的界定范围。
  • ; : 在前一个命令结束时,而忽略其返回值,继续执行下一个命令。
  • && : 在前一个命令结束时,若返回值为true,继续执行下一个命令。
  • || : 在前一个命令结束时,若返回值为false,继续执行下一个命令。
  • !: 执行history列表中的命令

...

假如我们需要在command line中将这些保留字元的功能关闭的话,就需要quoting处理了。在bash中,常用的quoting有如下三种方法:

hard quote:' '(单引号),凡在hard quote中的所有meta均被关闭。
soft quote:“”(双引号),在soft quote中大部份meta都会被关闭,但某些则保留(如$)。(注二:在soft quote中被豁免的具体meta清单,我不完全知道,有待大家补充,或透过实作来发现及理解。)
escape : \(反斜线),只有紧接在escape(跳脱字符)之后的单一meta才被关闭。
下面的例子将有助于我们对quoting的了解:

 $ A=B C #空白键未被关掉,作为IFS处理。 $ C: command not found. $ echo $A $ A="B C" #空白键已被关掉,仅作为空白键处理。 $ echo $A B C 

在第一次设定A变量时,由于空白键没被关闭,command line将被解读为:A=B然后碰到,再执行C命令

在第二次设定A变量时,由于空白键被置于soft quote中,因此被关闭,不再作为IFS:A=BC

事实上,空白键无论在soft quote还是在hard quote中,均会被关闭。Enter键亦然:

 $ A='B > C > ' $ echo "$A" B C 

在上例中,由于被置于hard quote当中,因此不再作为CR字符来处理。这里的单纯只是一个断行符号(new-line)而已,由于command line并没得到CR字符,因此进入第二个shell prompt(PS2,以>符号表示),command line并不会结束,直到第三行,我们输入的并不在hard quote里面,因此并没被关闭,此时,command line碰到CR字符,于是结束、交给shell来处理。
上例的要是被置于soft quote中的话,CR也会同样被关闭:

 $ A="B > C >" $ echo $A B C 

然而,由于echo $A时的变量没至于soft quote中,因此当变量替换完成后并作命令行重组时,会被解释为IFS,而不是解释为New Line字符。

同样的,用escape亦可关闭CR字符:

 $ A=B\ > C\ > $ echo $A BC 

上例中,第一个跟第二个均被escape字符关闭了,因此也不作为CR来处理,
但第三个由于没被跳脱,因此作为CR结束command line。

但由于键本身在shell meta中的特殊性,在\跳脱后面,仅仅取消其CR功能,而不会保留其IFS功能。

您或许发现光是一个键所产生的字符就有可能是如下这些可能:CR、IFS、NL(New Line)、FF(Form Feed)、NULL ...至于什么时候会解释为什么字符,这个我就没去深挖了,或是留给读者诸君自行慢慢摸索了…^_^

至于soft quote跟hard quote的不同,主要是对于某些meta的关闭与否,以$来作说明:

 $ A=B\ C $ echo "$A" B C $ echo '$A' $A 

在第一个echo命令行中,$被置于soft quote中,将不被关闭,因此继续处理变量替换,因此echo将A的变量值输出到荧幕,也就得到B C的结果。在第二个echo命令行中,$被置于hard quote中,则被关闭,因此$只是一个$符号,并不会用来作变量替换处理,因此结果是$符号后面接一个A字母:$A。

 # 练习与思考:如下结果为何不同? $ A=B\ C $ echo '"$A"' #最外面的是单引号 "$A" $ echo "'$A'" #最外面的是双引号 'B C' 

(提示:单引号及双引号,在quoting中均被关闭了。)
在CU的shell版里,我发现有很多初学者的问题,都与quoting理解的有关。比方说,若我们在awk或sed的命令参数中调用之前设定的一些变量时,常会问及为何不能的问题。要解决这些问题,关键点就是:
区分出shell meta与command meta

前面我们提到的那些meta,都是在command line中有特殊用途的,比方说{ }是将其内一系列command line置于不具名的函式中执行(可简单视为command block),但是,awk却需要用{ }来区分出awk的命令区段(BEGIN,MAIN,END)。若你在command line中如此输入:

 $ awk {print $0} 1.txt 

由于{ }在shell中并没关闭,那shell就将{print $0}视为command block,但同时又没有;符号作命令区隔,因此就出现awk的语法错误结果。要解决之,可用hard quote:

 $ awk '{print $0}' 1.txt 

上面的hard quote应好理解,就是将原本的{、、$(注三)、}这几个shell meta关闭,避免掉在shell中遭到处理,而完整的成为awk参数中的command meta。(注三:而其中的$0是awk内置的field number,而非awk的变量,awk自身的变量无需使用$。)

要是理解了hard quote的功能,再来理解soft quote与escape就不难:

 awk "{print \$0}" 1.txt awk \{print\ \$0\} 1.txt 

然而,若你要改变awk的$0的0值是从另一个shell变量读进呢?比方说:已有变量$A的值是0,那如何在command line中解决awk的$$A呢?你可以很直接否定掉hard quoe的方案:

 $ awk '{print $$A}' 1.txt 

那是因为$A的$在hard quote中是不能替换变量的。聪明的读者(如你!),经过本章学习,我想,应该可以解释为何我们可以使用如下操作了吧:

 A=0 awk "{print \$$A}" 1.txt awk \{print\ \$$A\} 1.txt awk '{print $'$A'}' 1.txt awk '{print $'"$A"'}' 1.txt #注:“$A”包在soft quote中 

或许,你能举出更多的方案呢….^_^

第5问:var=value? export前后差在哪?
这次让我们暂时丢开command line,先来了解一下bash变量(variable)吧…

所谓的变量,就是利用一个特定的“名称”(name)来存取一段可以变化的“值”(value)。

设定(set)
在bash中,你可以用“=”来设定或重新定义变量的内容:

提示: 本文由整理自网络,如有侵权请联系本站删除!
本站声明:
1、本站所有资源均来源于互联网,不保证100%完整、不提供任何技术支持;
2、本站所发布的文章以及附件仅限用于学习和研究目的;不得将用于商业或者非法用途;否则由此产生的法律后果,本站概不负责!

-六神源码网