1、什么是shell?
其实在接触linux之前我已经听过shell的大名,当时周围同学在聊shell编程,我对其一无所知。但令人惊奇的是,记忆力称得上糟糕的我竟然记住了这个名词。好了,废话少说。在上一篇(一)Linux? Ubuntu or CentOS? Linux安装中,已经讲述过。计算机使用者通过界面(shell,KDE等)与内核(Kernel)进行交流,以控制计算机硬件执行我们想要实现的功能。shell的字面意思是壳,也即包裹在核心(Kernel)外面的壳。是我们使用者用来与核心沟通的工具之一。
2、为什么要学习shell?
现在linux做的相当人性化。例如ubuntu的窗口界面,已经能完成大部分用户常用的操作。所以,为什么还要学习shell呢?答:虽然基于X-window的操作界面已经相当完善,功能也相当强,但它们都只是将能利用到的软件整合在一起的一组应用程序,并非是一个完整的套件。所以,当你升级其他套件的管理模块时,配置会很麻烦。甚至不同发布版本所设定的X-window接口也不相同,学习起来也有困扰。另外,当远程连接时,文字接口的传输速度比较快。最重要的是:它可以让你更深入了解linux。或许作为一般用户只学习操作界面也能解决绝大多数问题,尝尝linux的鲜。但是作为系统管理者或者开发者,学习shell是必要的。
3、Bash shell?
知道什么是shell之后,大致了解一下shell的版本。具体的不再详谈,Unix中常见的shell一般有Bourne Shell(sh)、在sun里预设的C Shell、商业上常用的K Shell和TCSH等。linux中使用的shell是Bourne Again Shell(简称Bash),它是Bourne Shell的增强版本,基于GNU架构发展而来。而在linux中可以使用哪些shell呢?目前Linux (以 CentOS 6.x 为例) 有多少我们可以使用的shell呢? 可以检查一下 /etc/shells 这个文件,发现有底下几种可以用的 shell:
/bin/sh (已经被 /bin/bash 所取代)
/bin/bash (就是 Linux 默认的 shell)
/bin/tcsh (整合 C Shell ,提供更多的功能)
/bin/csh (已经被 /bin/tcsh 所取代)
既然有这么多种shell,到底该学习哪一种呢?linux中默认的shell是Bash shell,所以我们先学好它就可以了。
4、Bash shell的功能
bash兼容sh。主要功能有:
1)命令记忆功能。bash能记忆使用过的命令,只需要在命令行处按上下键就可以找到之前/后输入的一个命令。在大多数发布版本中,默认的命令记忆功能可以记忆多达1000个命令。也即,你曾经下达过的命令几乎都被记录下来了。
这些命令都记录在你的家目录(/home/用户名这个目录)内的.bash_history文件中。不过,~/.bash_history(~指家目录,即/home/用户名这个目录。)记录的是上一次登录时运行过的命令,本次登录输入的命令则存储在缓存中,当注销系统后才会被记录到~/.bash_history文件中。
2)命令与文件补全功能([tab]键的妙用)
命令与文件补全功能可以让你:少打很多字;确定输入的数据正确。tab键的使用规则为:
[Tab] 接在一串命令的第一个字的后面,则为命令补全;
[Tab] 接在一串命令的第二个字以后时,则为文件补齐。
指令补全:如果在执行命令的时不想按太多按键,例如指令pcprofiledump,如果你输入了 pcprofile 之后,再按下 [Tab] 键,那么 bash 马上会自动的将后面的 dump 接上来!如果有重复的指令呢?按下两次 [Tab] 将会列出所有重复的指令!
文件名称补全:如果你用 vi 来读取某个文件时,例如 /etc/man.config,当你输入 vi /etc/man. 之后,直接按下 <tab> 键,则该文件名称就会被自动的补齐!
3)命令别名配置(alias)
假如我需要知道这个目录底下的所有文件 (包含隐藏档) 及所有的文件属性,那么我需要使用ls -al命令,稍微有些麻烦,有没有更快的办法?使用命令别名就可以。使用 alias将ls -al命令命名为lm,直接在bash中输入lm就可替代ls -al命令。具体做法为:
alias lm='ls -al'
4)工作控制(jobs)、前景背景控制
这部分在之后的资源管理部分会详细论述。使用前、背景的控制可以让工作更为顺利。工作控制(jobs)的可以让我们随时将工作丢到背景中执行,而不怕不小心使用了 Ctrl + C 停掉该程序。也可以在单用户环境中,达到多任务的目的。
5)Shell scripts
不知道各位有没有听过批处理文件,就是讲一堆指令写到一个文件中。在 Linux 中的shell scripts功能则更为强大,可以将日常生活当中常需要下达的连续指令写成一个文件,该文件可以通过交互式的方式来进行主机的侦测工作,也可以根据 shell 提供的环境变量及相关指令来进行设计,简直就和程序设计语言的功能相当了。
通配符(Wildcard)
除了完整的字符串之外,bash 还支持许多的通配符来帮助用户执行指令。例如,想知道 /usr/bin 目录中有多少以 X 为开头的文件怎么办?执行ls -l /usr/bin/X* 命令就可以。此外,还有其他可供利用的通配符帮助加快使用者的操作。
5、如何在Bash shell中下达指令?
command [-options] parameter1 parameter2 …即:命令 [-选项] 参数1 参数2 …
命令就是命令的名称,比如改变所在目录的命令cd;[]不实际出现,-出现,后面跟命令的选项。例如ls -al;参数即命令的参数。(注:命令太长时,可以使用\来延续指令到下一行)
6、变量与变量的设定
1)变量?
在输入指令ls的时候,系统如何知道ls指令放在哪里?这是因为有PATH变量,系统会通过这个变量中设定的路径依次去寻找该指令,如果未找到,则会输出command not found,如果找到,就执行指令。在写一个script的时候,如果里面有路径,且在很多地方被使用,有修改需求时逐个修改会很麻烦,如果有了变量,则只需要修改变量值,其他地方因为引用的都是变量所以就无需再修改。所以,变量是一组文字或符号等,用来取代一些设定或一串保留的数据
2)echo
刚介绍了变量的概念,那如何显示变量内容呢?使用echo指令。用法为echo $variable。例如echo $PATH
3)env
echo指令用来显示变量内容,那么我们如何知道系统中有哪些预设变量内容呢?使用env指令即可。
env是environment的简写,该指令将目前系统中的主要变量读出来!但是,我们不是还可以自订变量吗?因此,除了 env 这个读取环境变量的指令之外,还有一个可以将目前系统中所有的变量数据都读出来的指令,称为 set !set 除了会将上面的数据都读出来之外,还会有额外的这些信息也一起读出(通常都与使用者的设定有关!)
4)set
注:由于系统中变量太多,所以上面的图片只是env指令和set指令输出结果的一部分
5)自定义变量
如何自定义变量呢?如果想让该变量对所有使用者都有效,则需修改/etc/profile文件,如果只想对当前使用者有效,则先切换到当前使用者的家目录,然后修改.bashrc或.bash_profile文件。在其中命名变量并对变量赋值
6)变量的命名规则
刚才说到命名变量,对变量命名有一定的规则,主要如下:
- 变量与变量内容以等号『=』来连结;
- 等号两边不能直接接空格符;
- 变量名称只能是英文字母与数字,但是数字不能是开头字符;
- 若有空格符可以使用双引号『 " 』或单引号『 ' 』来将变量内容结合起来,但须要特别留意,双引号内的特殊字符可以保有变量特性,但是单引号内的特殊字符则仅为一般字符;
- 必要时需要以跳脱字符『 \ 』来将特殊符号(如Enter, $, \, 空格符, '等)变成一般符号;
- 在一串指令中,还需要藉由其它的指令提供的信息,可以使用 quote 『 ` command` 』;
- 若该变量为扩增变量内容时,则需以双引号及 $变量名称如:『 "$PATH":/home』继续累加内容;
- 若该变量需要在其它子程序执行,则需要以 export 来使变量可以动作,如『export PATH』;
- 通常大写字符为系统预设变量,自行设定变量可以使用小写字符,方便判断(纯粹依照使用者兴趣与嗜好);
- 取消变量的方法为:『unset 变量名称』。
7)一般变量设定
1name=shan <=错误,因为变量开头不能是数字
name = shan <=错误,因为等号两边不能直接接空格
name=shan <=正确
name=shan name <=错误,变量内容中有空格时,必须加双引号
name="shan name" <=正确
name="shan's name" <=正确
8)变量累加设定
name=$nameaa <=错误,需要对原变量加双引号
name="$name"aa <=正确,echo $name显示shan's nameaa。
name="$name":aa <=正确
name="$name:aa" <=正确
9)变量延伸到子程序
name="shan's name"<= 设定name变量
echo $name <=显示name变量内容
shan's name
/bin/bash <=打开一个bash子程序
echo $name <=显示name变量内容
<=会显示空字符串,因为name不能使用在子程序
exit <=退出子程序的bash shell
export name <=这样会将name变量延伸到子程序
10)指令中的指令
cd /lib/modules/`uname -r`/kernel
上式会限制性`uname -r`这个内嵌指令,然后将结果附加到整个指令中
11)取消变量设定:
unset name
12)在变量的设定中,单引号与双引号有什么不同呢?
答: 单引号与双引号的最大不同在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符,而不会有特殊符号。我们以底下的例子做说明:假设您定义了一个变量, name=shan ,现在想以 name 这个变量定义出 myname 显示 shan is me 这个内容,要如何订定呢?
[root @test root]# name=shan
[root @test root]# echo $name
VBird
[root @test root]# myname="$name is me"
[root @test root]# echo $myname
shan is me
[root @test root]# myname='$name is me'
[root @test root]# echo $myname
$name is me
13)使用了单引号的时候,那么 $name 将失去原有的变量内容,仅为一般字符的显示型态而已!这里必需要特别小心在意!
例:在指令下达的过程中,quote ( ` )(注:非') 这个符号代表的意义为何?
答: 在一串指令中,在 ` 之内的指令将会被先执行,而其执行出来的结果将做为外部的输入信息!例如 uname –r 会显示出目前的核心版本,而我们的核心版本在 /lib/modules 里面,因此,你可以先执行 uname –r 找出核心版本,然后再以『 cd 目录』到该目录下,当然也可以执行
cd /lib/modules/`uname –r`直接到该目录中。
14)变量的有效范围:
『变量的设定只在目前这个 shell 环境当中存在,在下个或者是在子程序中 ( 子 shell ) 将不会存在!』要让变量在下个程序也可以继续的使用,需要使用 export 这个命令!此外,其实除了 shell 的父、子程序外,在脚本( scripts )的编写当中,由于有的软件会使用到 2 个以上的 scripts 做为一个完整的套件!也就是说,假如你有两支程序,一支为 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 会去引用 scripts1.sh 的变数,在 scripts1.sh 当中设定的变量请『千万记得以 export 设定』,否则你的变量将无法在两个 scripts 之间互相被引用!当这个 scripts 执行完毕之后,刚刚在 scripts 当中设定的变量也就『失效』。
15)read,array,eval
使用read指令可以动态设定指令内容,而不是静态设定好再使用。
read 变量名,回车后会等待用户输入变量内容,例如输入read name[回车],再输入shan,再使用echo $name,输出结果为shan。
array制定一个变量数组,而eval则可以使用变量的变量。例如
day=2
year=day
echo \$$year <=\为转义字符,即将\后面的第一个$改变为一般字符
$day
eval echo \$$year <=加上eval后,\$$year的变为一个变量(即$day)
2
16)history、!number与!command
使用history命令可以查看过去输入的指令。输出的内容为:编号 指令名。如:66 ls -al。此时,我可以使用!66来执行ls -al指令,也可以使用!ls来执行ls -al指令。number为指令的序号,command为指令前几个字母。如果输入!!,则表示执行上一个指令(刚输入的那个指令)
7、Bash shell的设置文件
1)系统设定值:也即每个用户进入bash shell后,会先读取的设定文件。主要有以下几个:
/etc/profile:设定了几个重要的变量,如PATH,USER,MAIL,HOSTNAME,HISTSIZE,umask等。除此之外还有/etc/bashrc和/etc/man.config文件,具体内容可以百度或谷歌。
2)个人设定值:就是只针对当前使用者自己的文件。即在个人家目录中的几个隐藏文件。主要有:
~/.bash_profile:定义了个人路径与环境变量。可以在这里修改你的个人路径,也可以在 ~/.bashrc 这个个人设定的变量里头修改。
~/.bash_history:这个档案的用途在于将你曾经使用过的命令记录下来,而当你再次的以上下键搜寻或者直接以 history 搜寻的时候,就可以找到曾经使用过的指令。
~/.bash_logout:里面定义你注销 shell 的时候, BASH 会为你所做的事情!通常预设是只有 clear 清除屏幕这件事情而已。
8、source
如果我需要将目前的设定档的内容读入一次,需要重新 logout 再 login 才能够读入,那么有没有办法不注销而直接读入变量设定文件呢?当然可以,就使用 source 即可!具体格式为:source 变量设定文件
9、万用字符与特殊符号
符号 内容
* 万用字符,代表一个或多个字符(或数字)
? 万用字符,代表一个字母
# 批注,这个最常被使用在 script 当中,视为说明!
\ 跳脱符号,将『特殊字符或万用字符』还原成一般字符
| 分隔两个管线命令的界定;
; 连续性命令的界定(注意!与管线命令并不相同)
~ 使用者的家目录
$ 亦即是变量之前需要加的变量取代值
& 将指令变成背景下工作
! 逻辑运算意义上的『非』 not 的意思!
/ 路径分隔的符号
>, >> 输出导向,分别是『取代』与『累加』
' 单引号,不具有变量置换的功能
" 具有变量置换的功能!
` ` 两个『 ` 』中间为可以先执行的指令!
( ) 在中间为子 shell 的起始与结束
[ ] 在中间为字符的组合
{ } 在中间为命令区块的组合!
组合按键 执行结果
Ctrl + C 终止目前的命令
Ctrl + D 输入结束(EOF),例如邮件结束的时候;
Ctrl + M 就是 Enter 啦!
Ctrl + S 暂停屏幕的输出
Ctrl + Q 恢复屏幕的输出
Ctrl + U 在提示字符下,将整列命令删除
Ctrl + Z 『暂停』目前的命令
10、连续指令的下达方式:
两个指令先后写在一起,可以用以下三种方式写:
command1; command2。代表不论 command1执行结果为何,command2 都会被执行!
command1 && command2。代表如果command1没有错误,command2才会执行
command1 || command2。代表如果command1有错误,command2才会执行
11、绝对路径与相对路径
以/开头的路径为绝对路径,不以/开头的路径为相对路径。另外,'.'表示本层目录,‘..’表示上层目录,'~'表示家目录。
注:文件名前加'.'表示该文件为隐藏文件。
12、命令重导向
命令重导向:就是将你目前的所得资料存储到一个指定地方!最常用的,是将目前的屏幕输出数据转到文件中,可以这么写:ls -l / > test ,符号 > 就是将输出结果导向到 test 这个文件中的意思。
如果你只执行ls -l / ,屏幕会将根目录的档案与目录都列出在屏幕上;但是当使用 > 导向到 test 这个文件中时,则屏幕不会显示任何讯息,但是会将刚刚你执行的结果输出到 test 这个文件中。
注:重导向时,若该文件(就是 test )若不存在,系统会自动创建,如果当这个档案存在,那么系统就会先将这个档案内容清空,然后再将数据写入!
除了这个 > 的符号之外,在 bash 命令执行的过程中,主要有三种输出入的状况,分别是:
标准输入;代码为 0 ;或称为 stdin ;使用的方式为 <
标准输出:代码为 1 ;或称为 stdout;使用的方式为 1>
错误输出:代码为 2 ;或称为 stderr;使用的方式为 2>
基本的指令书写方式为:
指令 | 1> 1>> 2> 2>> < | 装置或文件 |
这里我们来说明一下命令重导向里面几个常用的符号与装置:
< :由 < 的右边读入参数档案;
> :将原本由屏幕输出的正确数据输出到 > 右边的 file ( 文件名称 ) 或 device ( 装置,如 printer )去;
>> :将原本由屏幕输出的正确数据输出到 >> 右边,与 > 不同的是,该文件将不会被覆盖,而新的数据将以『增加的方式』增加到该文件的最后面;
2> :将原本应该由屏幕输出的错误数据输出到 2> 的右边去。
/dev/null :可以说成是黑洞装置!
例如:
ls -al 1> list.txt 2> error.txt
将显示数据,正确的输出到list.txt,错误的输出到error.txt
ls -al 1> list.txt 2>&1
将显示的数据,无论正确或错误均输出到list.txt中
注:ls -al 1> list.txt 2> list.txt是错误的写法。
13、管道命令 ( pipe )
bash 命令执行的时候有输出的数据会出现!那么如果这群数据必需要经过几道手续之后才能得到我们所想要的格式,应该如何来设定?这就牵涉到逛到命令的问题了( pipe ),管道命令使用的是『 | 』这个界定符号!另外,管道命令与『连续下达命令』是不一样的,这点底下我们会再说明。底下我们先举一个例子来说明一下简单的管线命令。
假设我们要读取 last 这个指令中,那个 root 登入的『次数』应该怎么做?我们只需要『次数』。那么我所进行的步骤是:
执行 last ,将所有这个月的所有人登入数据取出来;
使用 grep 将上面的输出数据(stdout)当中的 root 撷取出来,其它的不要;
使用 wc 这个可以计算行数的指令将上一步的数据计算行数!
由于 last 的输出是一行代表一次登入,所以只要计算几行就代表登入几次的意思,所以啰!经由上面三个步骤,将 last 数据逐步的筛选,就可以得到我们的数据了!整个命令可以写成如下:
last
last | grep root
last | grep root | wc -l
你可以分别执行『 last 』然后再逐步增加为『 last | grep root 』,最后到上面那一行,那么就马上可以清楚的知道为何会这么做啰!这个管线命令『 | 』仅能处理经由前面一个指令传来的正确信息,也就是 standard output ( STDOUT ) 的信息,对于 stdandard error 并没有直接处理的能力,请记得。那么整体的管线命令可以使用下图表示之:
在每个管线的部分都是『指令』呢!而后一个指令的输入乃是由前一个指令的输出而来的!
下面我们来谈一谈一些基本的管线命令指令介绍:
1)cut
主要用于将同一行的数据进行分割,命令格式为:cut [-dcf] fields
参数说明:
-d:后面接的是用来分割的字符,预设为空格符
-c:后面接的是第几个字符
-f:后面接的是第几个区块
2)sort
主要用于对数据进行排序,命令格式为:sort [-t 分隔符] [(+起始)(-结束)] [-nru]
参数说明:
-t 分隔符:使用分隔符来隔开不同区间,预设是tab
+start -end:由第start区间排序到end区间
-n:用纯数字排序,否则就会以文字形态排序
-r:反向昂排序
-u:相同出现的一行,只列出一次
3)wc
主要用于计算档案内容,命令格式为:wc [-lmw]
参数说明:
-l:多少行
-m:多少字符
-w:多少字
4)uniq
重复的行删除掉只显示一个
5)tee
在命令重导向的时候,如果将数据输出到文件中,屏幕上就不会显示任何数据,如果需要在屏幕上也显示数据,加上tee就可以。
6)tr
在正则表达式中用的比较多。正则表达式在后面会讲。tr [-ds] set1
参数说明:
-d:删除set1这个字符串
-s:取代掉重复的字符
7)split
用来分割文件。具体格式为:split [-bl] 输入文件 输出文件前导字符
参数说明:
-b:以文件size来分
-l:以行数来分
写在末尾的一些话:
完整的Bash shell应该包括shell script,先写完这部分吧。写博客耗费的时间比看书多的多,不过写出来是一种总结。所以还是写一写的好~
转载请注明出处:http://blog.csdn.net/iAm333