我们知道,管理整个计算机硬件的其实是操作系统的内核(kernel),这个内核是需要被保护的,所以我们一般用户就只能通过shell来跟内核通信,以让内核达到我们所想要达到的工作。bash就是一个shell。
一,认识bash这个shell
- 对于操作系统(不论是Linux、UNIX或者是Windows)有点概念的朋友们大多听过这个名词,因为只要有“操作系统”那么就离不开Shell。我们必须通过Shell将我们输入的命令与内核通信,好让内核可以控制硬件来正确无误的工作。
- 其实shell的功能只是提供用户操作系统的一个接口,因此这个shell需要可以调用其他软件才好。我们在前面提到过的man, chamod, chown, vi, fdisk, mkfs等命令,这些命令都是独立的应用程序,但是我们可以通过shell(就是命令行模式)来操作这些应用程序,让这些应用程序调用内核来运行所需的工作。
- 也就是说,只要能够操作应用程序的接口都能够称为shell。狭义的shell指的是命令行方面的软件,包括本次要介绍的bash等。广义的shell则包括图形界面的软件,因为图形界面其实也能够操作各种应用程序来调用内核工作。
cat /etc/shells #查看系统有哪些shell
cat /etc/passwd #查看用户默认会取得哪一个shell,/bin/bash是linux默认的shell - bash shell的功能
(1)命令记忆能力:history
(2)命令补全功能:Tab按键的好处
(3)命令别名设置:alias
(4)作业控制、前台、后台控制(job control, foreground, background)
(5)程序脚本(shell script)
(6)通配符(Wildcard) - bash shell的内置命令:type
bash内置了很多命令,例如cd,umask等,那么怎么知道这个命令是来自于外部命令(指的是其他非bash所提供的命令)或是内置在bash当中的呢?利用type命令查看
type [-tpa] name #不加参数是,type会显示出name是外部命令还是bash内置命令
二,shell的变量功能
1.变量的显示与设置:echo, unset
echo $variable
echo $PATH
2.变量的设置规则
(1)变量与变量内容以一个等号“=”来连接,如下所示:
myname=Leo
(2)等号两边不能直接接空格符
(3)变量名称只能是英文字符与数字,但是开头字符不能是数字
(4)变量内容若有空格符可使用双引号或单引号将内容括起来,但是双引号内的特殊字符如$等,可以保有原本的特性:var=”lang is $LANG”
(5)可用转义符“\”将特殊符号(如[Enter], $, \, 空格符, !等)变成一般字符
(6)在一串命令中,还需要通过其他的命令提供的信息,可以使用反单引号括起来命令或$(命令):
version=$(uname -r)再echo $version可得“2.6.32-279.el6.i686”
(7)若该变量为了增加变量内容时,则可用“$变量名称”或${变量}累加内容,如下:
PATH=”$PATH”:/home/bin
(8)若该变量需要在其他子进程执行,则需要以export来使变量变成环境变量:
export PATH
(9)通常大写字符为系统默认变量,自行设置变量可以使用小写字符,方便判断
(10)取消变量的方法为使用“unset 变量名称”,例如:unset myname
3.环境变量的功能
环境变量可以帮助我们达到很多功能,包括主文件夹的变换、提示符的显示、执行文件查找的路径等。
1.用env查看环境变量与常见变量说明
env是environment的简写
2.用set查看所有变量(含环境变量与自定义变量)
4.影响显示结果的语系变量(locale)
linux支持了多少语系可以由下面的命令查询到:locale -a
5.变量的有效范围
变量也有使用的范围的,被export后的变量,我们可以称它为环境变量。环境变量可以被子进程所引用,但是其他的自定义变量内容就不会存在于子进程中。
6.变量的键盘读取,数据与声明:read, array, declare
(1)read:要读取来自键盘输入的变量,就是用read这个命令,这个命令最常被用在shell script的编写当中。
read [-pt] variable
-p:后面可以接提示符
-t:后面可以接等待的“秒数”
例如:read atest
This is a test #此时光标会等待你输入内容,输入之后
echo $atest #显示出前面输入的变量内容
再如:read -p “Please input your name: ” -t 30 named
Please input your name: Leo #假如我输入Leo
echo $named #结果显示Leo
(2)declare/typeset
declare或typeset是一样的功能,就是声明变量的类型。如果使用declare后面没有接任何参数,那么bash就会主动将所有的变量名与内容全部调出来,就好像使用set一样。
declare [-aixr] variable
参数:
-a:将后面名为variable的变量定义成数组(array)类型
-i:将后面名为variable的变量定义成整数数字(integer)类型
-x:用法与export一样,就是将后面的variable变成环境变量
-r:将变量设置成为readonly类型,该变量不可被更改内容,也不能重设
三,命令别名与历史命令
1.命令别名设置:alias, unalias
示例:
alias lm=’ls -l | more’
alias rm=’rm -i’
alias #查询目前有哪些命令别名
unalias lm #取消别名设置
2.历史命令:history
命令格式:
history [n]
history [-c]
history [-raw] histfiles
n:数字,是要列出最近的n条命令行的意思
-c:将目前的shell中的所有history内容全部消除
-a:将目前新增的history命令新增如histfiles中,若没有加histfiles,则默认写入~/.bash_history
-r:将histfiles的内容读到目前这个shell的history中
-w:将目前history记忆内容写入histfiles中
四,Bash Shell的操作环境
1.路径与命令查找顺序
我知道系统里面其实有不少的ls命令,或者是包括内置的echo命令,那么来想一想,如果一个命令(比如ls)被执行时,到底哪一个ls被拿来运行?基本上,命令运行的顺序可以这样看:
(1)以相对/绝对路径执行命令,例如/bin/ls 或 ./ls
(2)由alias找到该命令来执行
(3)由bash内置的(builtin)命令来执行
(4)通过$PATH这个变量的顺序找到的第一个命令来执行
2.bash的登录与欢迎信息:/etc/issue, /etc/motd
通过命令cat /etc/issue查看登录欢迎信息,issue内的各代码意义:
\d:本地端时间的日期
\l:显示第几个终端机接口
\m:显示硬件的等价(i386/i486/i686…)
\n:显示主机的网络名称
\o:显示domain name
\r:操作系统的版本(相当于uname -r)
\t:显示本地端时间的时间
\s:操作系统的名称
\v:操作系统的版本
3.通配符与特殊符号
在bash的操作环境中还有一个非常有用的功能,那就是通配符(wildcard)。下面列出常用的通配符:
*:代表0个到无穷多个任意字符
?:代表一定有一个任意字符
[]:同样代表一定有一个在中括号内的字符(非任意字符),例如[abcd]代表移动有一个字符,可能是abcd中任何一个。
[-]:若有减号在括号内时,代表在编码顺序的所有字符,例如[0-9]代表0到9之间所有数字。
[^]:若中括号内的第一个字符为指数符号(^),那表示反向选择,例如[^abc]表示一定有一个字符,只要是非abc即可。
除了通配符之外,bash环境中的特殊符号还有下面汇总的这些:
#:批注符号,这个最常被使用在script当中,视为说明,其后的数据均不执行
\:转移符号,将“特殊字符或通配符”还原成一般字符
|:管道(pipe),分隔两个管道命令的界定
;:连续命令执行分隔符,连续性命令的界定
~:用户的主文件夹
$:使用变量前导符,即是变量之前需要加的变量替代值
&:作业控制(job control),将命令变成背景下工作
!:逻辑运算意义上的“非”的意思
/:目录符号,路径分隔的符号
>, >>:数据流重定向,输出导向,分别是“替换”与“累加”
<, <<:数据流重定向,输入导向
‘ ‘:单引号,不具有变量置换的功能
“”:双引号,具有变量置换的功能
:两个`中间为可以先执行的命令,也可使用$()
():在中间为子shell的起始与结束
{}:在中间为命令块的组合
五,数据流重定向
数据流重定向(redirect)就是将某个命令执行应该要出现在屏幕上的数据传输到其他的地方,例如文件或者是设备(打印机之类)。
1.数据流重定向可以将standard output(stdout)与standard error ooutput(stderr)分别传送到其他的文件或设备去,而分别传送所用的特殊字符则如下所示:
(1)标准输入(stdin):代码为0,使用<或<<
(2)标准输出(stdout):代码为1,使用>或>>(1>,1>>)
(3)标准错误输出(stderr):代码为2,使用2>或2>>
示例:
ll / > ~/rootfile #查看系统根目录下各目录的文件名、权限与属性,并记录下来
并且:
(1)1>:以覆盖的方法将正确的数据输出到指定的文件或设备上
(2)1>>:以累加的方法将正确的数据输出到指定的文件或设备上
(3)2>:以覆盖飞方法将错误的数据输出到指定的文件或设备上
(4)2>>:以累加的方法将错误的数据输出到指定的文件或设备上
示例:
(1)find /home -name .bashrc >list_right 2> list_error #将stdout与stderr分别存到不同的文件去
(2)将错误的数据丢弃,屏幕上显示正确的数据:
find /home -name .bashrc 2> /dev/null #/dev/null垃圾桶黑洞设备
(3)将正确与错误的数据全部写在一个文件中去:
find /home -name .bashrc > list 2> list #错误
find /home -name .bashrc > list 2>&1
find /home -name .bashrc &> list
2.standard input:<与<<
前面介绍了stdout、stderr,那么<的意思是将原本需要由键盘输入的数据改由文件内容来替代。
3.命令执行的判断依据:; , &&, ||
某些情况下,很多命令我们想要一次输入去执行,而不想要分次执行时,有两个选择,一是通过后面将要介绍的shell script编写脚本去执行;二是通过下面的介绍的方法:
(1)cmd;cmd(不考虑命令相关性的连续命令执行)
sync; sync; shutdown -h now
(2)$?(命令回传码)与&&或||
若前一个命令执行的结果为正确,在Linux下面会回传一个$?=0的值。
cmd1 && cmd2:若cmd1执行完毕且正确执行($?=0),则开始执行cmd2,若cmd1执行完毕且错误($?!=0),则cmd2不执行
cmd1 || cmd2:若cmd1执行完毕且正确执行,则cmd2不执行,若cmd1执行完毕且错误,则开始执行cmd2
六,管道命令(pipe)
如前所述,bash命令执行的时候有输出的数据就会出现,那么如果这些数据必须经过几道手续之后才能得到我们所想要的格式,应该如何来设置呢?这里就涉及到了管道命令的相关知识了。管道命令使用的是“ | ”这个界定符号。另外管道命令与“连续执行命令”是不一样的。
假设我想知道/etc/下面有多少文件,那么可以利用ls /etc来查阅。不过因为/etc下文件太多,我们可以通过less命令协助:
ls -al /etc | less #这个管道命令“|”仅能处理经由前面一个命令传来的正确信息,也就是standard output的信息,对于standard error并没有直接处理能力。
- 选取命令:cut, grep
(1)cut
这个命令可以将信息的某一段“切”出来,处理的信息是以“行”为单位。
cut -d‘分隔字符’ -f fields #用于分隔字符
cut -c 字符范围 #用于排列整齐的信息
-d:后面接分隔字符,与-f一起使用
-f:依据-d的分隔字符将一段信息割成书断,用-f取出第几段的意思
-c:以字符(characters)的单位取出固定字符区间
示例:
echo $PATH | cut -d ‘:’ -f 3,5 #将PATH变量取出,我们要找第3,第5的路径
export | cut -c 12- #将export输出的信息取得第12字符以后的所有字符串
(2)grep
grep则是分析一行信息,若当中有我们所需要的信息,就将该行拿出来
grep [-acinv] [–color=auto] ‘查找字符串’ filename
-a:将binary文件以text文件的方式查看数据
-c:计算找到’查找字符串’的次数
-i:忽略大小写的不同,所以大小写视为相同
-n:顺便输出行号
-v:反向选择,即显示出没有’查找字符串’内容的那一行
–color=auto:可以将找到的关键字部分加上颜色显示出来
示例:
last | grep ‘root’ #将last当中有出现root的那一行取出来
last | grep -v ‘root’ #与上面的相反,只要没有root的就取出
last | grep ‘root’ | cut -d ‘ ‘ -f 1 #将last信息输出,只要有root就取出,并且仅取第一列
2. 排序命令:sort, wc, uniq
很多时候,我们会去计算数据里的相同类型的数据总数,举例来说,我们使用last可以查得这个月份有哪些用户登录了主机者。那么我们可以针对每个用户查出他们的总登录次数。
(1)sort可以帮我们进行排序,而且可以依据不同的数据类型来排序
sort [-fbMnrtuk] [file or stdin]
-f:忽略大小写的差异
-b:忽略最前面的空格符部分
-M:以月份的名字来排序,例如JAN, DEC等的排序方法
-n:使用“纯数字”进行排序(默认以文字类型来排序)
-r:反向排序
-u:就是uniq,相同的数据中,仅出现一行代表
-t:分隔符,默认是用Tab键来分隔
-k:以那个区间(field)来进行排序的意思
示例:
cat /etc/passwd | sort #将账号进行排序
cat /etc/passwd | sort -t ‘:’ -k 3 #/etc/passwd内容是以:来分隔的,我们以第三列来排序
(2)uniq
如果我们排序完成了,想要将重复的数据仅列出一个显示,可以使用uniq来实现
uniq [-ic]
-i:忽略大小写
-c:进行计数
示例:
last | cut -d ‘ ‘ -f1 | sort |uniq #使用last将账号列出,仅取出账号列,进行排序后仅取出一位
last | cut -d ‘ ‘ -f1 | sort | uniq -c #在上个例子的基础上,基础每个人的登录总次数
(3)wc
如果我们想要知道/etc/man.config这个文件里面有多少个字?多少行?多少字符的话,可以通过wc命令来实现
wc [-lwm]
-l:仅列出行
-w:仅列出多少字(英文单字)
-m:多少字符
示例:
cat /etc/man.config | wc #统计文件中有多少字、行、字符数
3.双向重定向:tee
前面我们知道>会将数据流整个传送给文件或设备,因此我们除非去读取该文件或设备,否则就无法继续利用这个数据流。那么万一我想要将这个数据流的处理过程中某段信息存下来,可以利用tee实现:tee会同时将数据流送与文件与屏幕,而输出到屏幕的是stdout,可以让下个命令继续处理。
tee [-a] file
-a:以累加(append)的方式,将数据加入file中
示例:
last | tee last.list | cut -d ” ” -f1 #将last的输出存一份到last.list文件中
ls -l /home | tee ~homefile | more #将ls的数据存一份到~/homefile, 同时屏幕也有输出信息
ls -l / | tee -a ~/homefile | more #要注意,tee后接的文件会被覆盖,除非加上-a,将信息累加
参考:Linux私房菜第三版
quanmian!