Linux bash介绍

一、bash与shell介绍

管理整个电脑硬件的核心是操作系统的内核(kernel),内核是被保护的,一般使用者只能通过shell和内核进行沟通,来让内核进行我们想要的工作。接下来介绍shell,以及我们为什么要使用bash。

1.1 硬件、内核与shell

在讨论shell前,我们先复习下电脑的运行情况。举个例子来说,当我们要电脑传输出来“音乐”的时候,我们的电脑需要什么?

  • 硬件:首先我们的电脑硬件需要有“音效卡芯片”这个配置,用来产生声音
  • 内核管理:操作系统的内核可以支撑芯片组,当然还需要芯片的驱动程序
  • 应用程序:需要使用者(也就是我们)输入发生声音的指令

这就是最基本的一个输出声音所需要的步骤。也就是说,我们必须要“输入”一个指令后,“硬件”才会通过我们下达的指令来工作。通过内核,我们可以控制硬件执行我们所下达的指令,这也就是说,我们必须要通过shell将我们输入的指令与内核进行沟通,来让内核可以控制硬件来正确无误的进行工作。整个工作过程可以用如下的图片进行描述:
在这里插入图片描述
操作系统本质是一组软件,但是这组软件不能被使用者任意使用,因为其管理着所有硬件的功能。如果操作者使用不当,将会导致整个操作系统崩溃。但是我们总是需要让使用者来使用操作系统,所以就有了在操作系统上发展的应用程序。使用者可以通过这些应用程序来指挥操作系统,让内核来达成我们需要的硬件任务。在下图中,应用程序在最外层,如同鸡蛋的外壳一样,所以也就被称为壳程序(shell)了。
在这里插入图片描述
shell的功能只是提供使用者操作整个操作系统的一个界面,因此它可以调用其他程序。很多指令例如manchmodchown等都是独立的应用程序,但是我们可以通过shell(就是指令列模式)来操作这些应用程序,使其呼叫内核来完成所需要的工作。

推广来讲,只要能够操作应用程序的界面都能够称为shell。狭义的shell指的是指令列方面的软件,包括bash等。广义的shell则包括所有图形界面的软件,因为图形界面其实也能够操作各种应用程序来呼叫内核工作。

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

接下来了解下Linux使用的是哪一个shell。早期的Unix有很多不同的shell版本,例如常听到的Bourne Shell(SH)、在sun里面预设的C Shell、商业上常用的K Shell、还有TCSH等等,每一种Shell都各有其特点。而Linux使用的版本称为Bourne Again Shell(简称bash),这个Shell是Bourne Shell的增强版本,也是基于GNU的架构下发展出来的。

通过查看/etc/shells这个文件,我们可以获取当前可用的shell:
在这里插入图片描述
其中:

  • /bin/sh:已经被/bin/bash所取代
  • /bin/bash:就是Linux预设的shell
  • /bin/tcsh:整合C Shell,提供更多的功能
  • /bin/csh:已经被/bin/tcsh所取代

为什么系统上shell要写入/etc/shells这个文件呢?这是因为系统某些服务在运行过程中,会去检查使用者能够使用的shells,而这些shell的查询就是通过/etc/shells这个档案。

举例来说,某些FTP网站会去检查使用者的可用shell,而如果我们不想要让这些使用者使用FTP以外的主机资源时,可能会给予该使用者一些“怪怪”的shell,让使用者无法以其他服务登入主机。这个时候,我们就需要将这些“怪怪”的shell写到/etc/shells当中。

在我们登陆的时候,系统就会分配给我们一个shell来让我们进行工作,这个登入的shell就记录在/etc/passwd文件中:
在这里插入图片描述
在每一行的最后一个信息,就是我们登入后可以取得的预设的shell了,在第一行可以看到root的预设shell是/bin/bash。

1.3 Bash Shell的功能

bash是GNU计划中重要的工具软件之一,目前也是Linux distributions的标准shell。bash是兼容sh,并且依据一些使用者的需求而加强的shell版本。bash的优点主要如下所示:


命令编修能力(history):

bash的功能里面,一个相当有用的就是“能够记忆使用过的指令”,只需要我们在指令列按上下键,我们就可以找到前/后一个输入的指令。在很多的distribution的里面,预设的指令记忆功能可以达到1000个,也就是说,我们曾经下达过的指令几乎都被记录下来了。

这些指令被记录在家目录下的.bash_history里面。不过需要留意的是~/.bash_history记录的是前一次登入前所执行过的指令,而至于这一次登陆所执行的指令都被暂存在内存中,当我们成功登出系统后,该指令才会记录到.bash_history当中。

这样做的最大的好处是可以查询曾经做过的举动。如此可以知道我们的执行步骤,那么就可以追踪我们曾下达过的指令,以作为除错的重要流程。但是如此以来也有一个烦恼,如果我们被黑客入侵了,那么他只需要翻阅我们曾经执行过的指令,刚好我们的指令又和系统有关(例如直接输入MySQL的密码在指令列上面),那我们的服务器可能被入侵。


命令与文件补全功能([tab]键)

  • 在一串指令的第一个字后面使用tab时,为命令补全
  • 在一串指令的第二个字后面使用tab时,为文件不去按
  • 如果安装了tab-completion软件,则在某些指令后面使用tab时,可以进行选项/参数的补全

命令别名设定功能(alias)

如果我们要知道一个目录下的所有文件及档案属性,可以使用ls -al命令,但这个命令有些长,我们这时可以使用别名,例如用lm取代上面的命令。这表示lmls -al的功能是等价的。我们在指令列中输入alias就可以知道目前的命令别名有哪些,同样可以用如下的方式来设定别名:

alias lm = 'ls-al'

1.4 查询指令是否为bash shell的内部指令:type

为了方便shell的操作,bash已经内建了很多指令,例如cd,还有例如umask等等指令。如果我们想知道一个指令是来自于外部指令(非bash所提供的指令)还是已经内建在bash当中的,那么可以使用type,type的使用说明:

type [-tpa] name

选项与参数:

  • 不加任何选项与参数时,type会显示出name是外部指令还是bash内建指令

  • 加入-t选项时,type会将name用如下方式显示出它的意义:
    file:表示外部指令
    alias:表示该指令为命令别名所设定的名称
    builtin:表示该指令为bash内建的指令功能

  • 加入-p选项时,如果后面接的name为外部指令时,才会显示完整文件名

  • 加入-a选项时,会从PATH变量定义的路径中,将所有含name的指令都列出来,包含alias

範例一:查詢一下 ls 這個指令是否為 bash 內建?
[dmtsai@study ~]$ type ls
ls is aliased to `ls --color=auto' <==未加任何參數,列出 ls 的最主要使用情況
[dmtsai@study ~]$ type -t ls
alias                              <==僅列出 ls 執行時的依據
[dmtsai@study ~]$ type -a ls
ls is aliased to `ls --color=auto' <==最先使用 aliase
ls is /usr/bin/ls                  <==還有找到外部指令在 /bin/ls

範例二:那麼 cd 呢?
[dmtsai@study ~]$ type cd
cd is a shell builtin              <==看到了嗎? cd 是 shell 內建指令

通过type这个指令我们可以知道每个指令是否为bash的内建指令。此外,由于利用type搜寻后面的名称时,如果后面接的名称不能以可执行文件的形式被找到,那么这个名称是不会被显示出来的。

二、shell的变量功能

/待补充

五、数据流重定向

数据流重定向就是将某个指令执行后应该要出现在屏幕上的数据,传输到其他地方,例如文件或者设备(例如打印机)。在Linux的文字模式下数据流重定向是十分重要的。

5.1 什么是数据流重定向

一般来说,如果我们要执行一个指令,通常是这样的:
在这里插入图片描述
当我们执行一个指令的时候,这个指令可能会由文件读入数据,经过数据后,再将数据输出到屏幕上。在上图中,standard output和standard error分别代表标准输出和标准错误输出,这两个预设都是输出到屏幕上的。接下来介绍下标准输出和标准错误输出:


标准输出和标准错误输出:

简单来说,标准输出指的是指令执行所传回的正确的信息,而标准错误输出可以理解为指令执行失败后,所传回的错误信息。举个例子,我们的系统预设了/etc/crontab但却没有预设/etc/testtest,此时如果我们执行cat /etc/crontab /etc/testtest这个指令时,cat会进行:

  • 标准输出:读取/etc/crontab后,将该文件内容显示到屏幕上
  • 标准错误输出:因为无法找到/etc/testtest,因此在屏幕上显示错误信息

不管正确或错误的数据都是预设输出到屏幕上,这样会使得屏幕显得很乱。所以我们需要通过某种机制将这两种数据分开,这里我们就需要用到数据重定向。数据重定向可以将标准输出和标准错误分别传送到其他的文件或设备中,分别所用的字符如下所示:

  • 标准输入(stdin):代码为0,使用<或<<
  • 标准输出(stdout):代码为1,使用>或>>
  • 标准错误输出(stderr):代码为2,使用2>或2>>

我们以下面的例子来理解下使用过程:

首先我们先观察下系统根目录/下各目录的文件名、权限及属性:
在这里插入图片描述
接着我们将输出重定向到~/rootfile这个原本不存在的文件,然后可以看到我们新建了这个文件:
在这里插入图片描述
我们查看这个文件内的内容:
在这里插入图片描述
可以看到原本输出到屏幕的内容被重定向到了我们指定的文件中,此时如果我们再次执行ll /home > ~/rootfile后,那么这个文件内的内容就会变成仅有ll /home输出的数据而已,原来ll的数据就不见了,文件的建立方式是:

  • 该文件(本例中是~/rootfile)若不存在,系统会自动建立这个文件
  • 当这个文件存在的时候,那么系统会先将这个文件的内容清空,然后再将资料写入

如果我们想要累加数据而不是清空数据,那么我们可以使用>>符号,以上面的例子来说,我们使用ll / >> ~/rootfile即可。如此一来,当~/rootfile不存在时系统会主动建立这个文件,当文件存在的时候数据会累加进这个文件中。

上面提到的时standard output的正确文件,那么如果是standard error output的错误文件呢?这时可以通过2>及2>>。同样是覆盖(2>)与累加(2>>)的特性。

在上面提及了标准输出的代码是1而标准错误的代码是2,仅存在>>时,我们认为预设的是1,所以这个2也比较好理解,总的来说:

  • 1>:以覆盖的方式将正确的数据输出到指定的文件或设备上
  • 1>>:以累加的方式将正确的数据输出到指定的文件或设备上
  • 2>:以覆盖的方式将错误的数据输出到指定的文件或设备上
  • 2>>:以累加的方式将错误的数据输出到指定的文件或设备上

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

如果我们知道错误会发生,那么我们如何将错误信息忽略到或者不存储呢?这个时候我们可以使用黑洞装置/dev/null:

如下是一个报错的例子:
在这里插入图片描述
我们可以利用/dev/null来丢弃错误的数据,只在屏幕上显示正确的数据:
在这里插入图片描述


标准输入:<和<<

了解了stderr和stdout后,我们来看下<是什么意思。以最简单的语法来说,就是将原本需要由键盘输入的数据,改成由文件内容来取代。我们先通过cat指令操作来了解下什么叫做键盘输入:

通过cat指令来建立一个文件的简单流程:
在这里插入图片描述
在上面的输入过程中,我们可以按下ctrl+d退出输入。

接下来看下这个文件中的内容:
在这里插入图片描述
在上面的例子中,我们通过键盘输入了catfile的内容,接下来我们通过文件来替代键盘的输入,也就是说,通过某个文件的内容来替代键盘的输入:
在这里插入图片描述
可以看出,这两个文件的大小一摸一样,里面的内容也是完全一致的。这种用法非常常用,尤其是在类似mail这种指令的使用上。

/待补充

5.2 命令执行的判断依据::、&&、||

在很多情况下,我们想要一次执行很多指令,而不想要分次执行。这时候我们有两个选择,一个是编写一个shell script,另外一种是通过如下的方式来一次输入多重指令:


cmd;cmd(两个连续指令间利用分号进行分割)

在某些时候,我们希望可以一次执行多个指令,例如在关机的时候我们希望可以先执行两次sync同步化写入磁盘后才关闭电脑,那么我们可以这样做:
在这里插入图片描述
在这种表示方式下,分号前的指令执行完后就会立即接着执行后面的指令。如果前一个指令是否成功的执行与后一个指令是否要执行有关,那么需要用到&&或||


$?(指令回传值)与&&或||

这种情况下,两个指令间有依赖性,而这个依赖性主要判断的地方

/待补充

六、管道命令(pipe)

bash命令执行时的时候会输出一部分数据,如果我们需要这些数据经过一些处理,得到我们想要的格式,那么应该如何设定?这就涉及到管道命令(pipe),管道命令使用|这个符号,接下来以一个例子来说明下简单的管道命令:

假设我们想要知道/etc/下有多少文件,那么可以利用ls /etc来查询,不过,因为/etc下面的文件太多,导致屏幕会一下子占满,看不清之前输出的是什么。此时,我们可以通过less指令的协助。利用ls -al /etc | less命令,我们使用ls指令输出后的内容,就能够被less读取,并且利用less的功能,我们就能够前后翻动相关的信息。

其实管道命令|仅能够处理经由前一个指令传来的正确信息,也就是standard output的信息,对于standard error并没有直接处理的能力,整体的管道命令可以使用下图表示:
在这里插入图片描述
在每个管道后面接的第一个数据一定是指令,并且这个指令必须要能够接收standard input的数据才可以,这样的指令也被称为管道指令,例如less、more、head、tail等都是可以接收standard input的管道命令。至于ls、cp、mv等都不是管道命令,因为它们不接受来自于stdin的数据,也就是说,管道命令主要有两点比较需要注意的地方:

  • 管道命令仅会处理standard output,对于standard error output会予以忽略
  • 管道命令必须要能够接收来自前一个指令的数据成为standard input继续处理才行

接下来对一些常用的管道命令进行介绍:

6.1 提取指令:cut、grep

cut

这个指令可以将一段信息的某一段截取出来,处理的信息是以行为单位的。

cut指令的语法如下:

cut -d '分割字符' -f fields
选项及参数:
-d:后面的字符是我们进行分割的依据,和-f一起使用
-f:依据-d后面的分割字符将一段信息分割为几段,fields指明了是第几段
cut -c 字符取间
选项及参数:
-c:以字符的单位取出固定字符区间

接下来我们对上面的两种用法进行举例

测试用例一(取出PATH变量中的路径):
在这里插入图片描述
输出可以依照:进行如下的划分:

/usr/local/sbin:/usr/local/bin:/usr/sbin:usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
|       1      |       2      |     3   |   4   |  5  |  6 |    7     |       8        |    9    |  

接下来我们进行测试:
在这里插入图片描述
第一个命令输出了分割出的第五个路径,第二个命令输出了第三个和第五个路径。

测试用例二(取出export输出信息后某个字符后的所有字符):

在这里插入图片描述
在这里插入图片描述
可以看到通过上面的例子,declare -X字符串就被从输出中除去了,利用-c选项,我们可以处理比较有格式的输出信息。

cut的主要用途在于将同一行里面的资料进行分解,最常用在分析一些数据或文字资料时,这是因为有时我们会以某个字符当作分割的参数,然后用来将数据进行分割,来获得我们所需的资料。


grep:

cut指令是取出一行信息中我们所需要的部分,而grep则是分析一行信息,如果当中有我们所需要的信息,就将该行取出来,简单的语法是这样的:

grep [-acinv] [--color=auto] '搜索的字符串' filename
选项与参数:
-a:将binary的文件以text文件的形式搜索数据
-c:计算找到'搜索的字符串'的次数
-i:忽略大小写的不同,所以大小写皆视为相同
-n:顺便输出行号
-v:反向选择,即显示出没有'搜索的字符串'内容的那一行
--color=auto:可以将找到的关键字部分加上颜色的显示

使用举例(找到last输出中的boot):

直接执行last输出如下:
在这里插入图片描述
将出现boot的那一行取出来:
在这里插入图片描述

6.2 排序指令:sort、wc、uniq

参考-鸟哥的Linux私房菜

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值