一、Shell简介
1、Shell简介
在过去没有图形化界面的年代,如果我们需要与操作系统进行交互,是无法使用鼠标进行操作的,而是在终端的界面内输入相关的指令让计算机完成相应的操作。诸如早期的Unix系统、微软的DOS系统、早期Linux系统(例如较早版本的RedHat)等都是采取这种方式来和用于进行交互的。
随着时间的发展,计算机图形化程度不断提高,各式各样的图形化界面系统(代表:Windows系列)开始安装在用户的电脑上,用户在图形化界面(即桌面的环境)下,通过鼠标的移动、点击、双击、拖拽等操作就可以实现文件的移动、复制、粘贴、剪切、删除等一系列操作。这样做不仅方便用户使用系统,而且还大大增加了操作系统与用户的亲和性。
但是,使用鼠标进行系统操作的效率是十分低下的。而且在某些特殊情况下(例如图形化界面全面崩溃),使用指令似乎是唯一一种与操作系统打交道的方式。因此,Linux系统仍然保留用户通过指令与操作系统交互的方式,这种方式就是通过Shell。使用Shell指令与系统进行交互要比图形化界面更加的高效直接。
//Windows系统内现在仍然保留输入指令进行交互的模式,有两个软件可以实现:cmd.exe与powershell.exe
Shell,中文翻译为“壳”(相对于kernel“核”),是用于保护操作系统内核的工具。操作系统的核心kernel管理整个计算机硬件相关部分,因此这部分是需要被保护的!为了保护内核,隔离用户与内核,我们引入了Shell的概念,用户若想与操作系统的内核打交道必须通过Shell进行沟通。
2、Shell工作流程
下面通过一个简单的示例来说明Shell的工作。例如,当我们需要让计算机播放音乐,我们必须需要以下几样东西:
1.硬件:如果需要电脑播放音乐,必须有“声卡”这个设备,否则无法发声
2.管理程序:操作系统需要支持这个设备并且具有这个设备的驱动程序
3.应用程序:用户使用软件(或某些指令)让电脑发出声音
Shell工作的流程是:
1.用户在命令行提示符下键入命令(播放音乐),开始与Shell交互
2.Shell将用户的指令转化为内核能够理解的指令并传递给内核
3.内核做出相应的操作(调用声卡驱动程序等),直至控制相关的硬件设备(声卡发声)
4.Shell将运行结果反馈给用户(成功/失败)
简单来说,Shell接收用户发出的指令并且传递给内核Kernel,内核再进行后续的工作。这样,用户无需也不能直接访问内核,不仅大大方便了用户使用操作系统,也隔离了用户与内核,内核被Shell保护。
//见附图3
Shell为用户提供了操作系统的接口,我们之前学习过的在Terminal上运行的指令/程序都是独立的程序,运行于Shell层上。因此这些指令又被称为Shell命令。若想同时自动执行多条指令,还可以将Shell命令写成Shell脚本文件,交给Shell批量执行。
3、Shell分类
Unix系统下的Unix Shell发展至今,由不同机构、不同人员、不同目的开发出了各种不同类型的Shell程序。目前比较流行的有:
1.Bourne Shell(简称sh):
由AT&T贝尔实验室的Bourne开发,是Unix系统上的第一个Shell程序,一经问世就成为了工业标准。现在几乎所有的Unix/Linux系统都支持它。不过sh的功能较薄弱,且没有历史记录等重要功能,因此目前大多数操作系统将其作为应急Shell使用。
//注意:在Ubuntu中,出于执行效率的考虑,sh已经更改为dash(即sh是dash的软链接)
2.C Shell(简称csh):
由加利福尼亚大学伯克利分校研发,最初的研发目的是为了改进sh的缺点。由于其Shell脚本的风格接近C语言因此最初受到广大C语言用户喜爱。不过由于其健壮性较弱,目前的应用并不十分广泛
3.Korn Shell(简称ksh):
由David Korn开发,最初是为了解决sh的用户交互问题以及改进csh的“怪异的”脚本编程风格。使用ksh需要许可证,因此应用并不广泛。
4.Bourne Again Shell(简称bash):
由AT&T贝尔实验室的Bourne开发,sh的增强版。随着bash的不断完善,它已经成为了最流行的shell。
5.Debian Almquist Shell(简称dash):
比bash小,只需占用较小的磁盘空间,而且需要的库更少。不过相对于bash功能也更少。
查看自己的终端的Shell类型:指令 echo $SHELL
二、Shell命令的格式与符号
1、命令提示符
Shell提供命令提示符表示该命令行的开始,用户在命令提示符后面输入命令,按下ENTER键表示提交命令。
命令提示符的格式为:
username@hostname:direction $/#
其中:
username:表示用户名,显示当前登陆用户的账号名
hostname:表示主机名,显示当前登陆的主机名
direction:表示路径名,显示当前所处的路径。其中根目录用/表示,用户工作目录用~表示
$或#:表示命令开始位置,普通用户为$,而超级用户为#
练习:说出以下命令提示符所蕴含的信息:
1.linux@Ubuntu:~/Examples $
2.root@Ubuntu:/root #
2、命令格式
一条Shell命令包含三个要素:命令名称、可选项、参数。命令名称是必须的,而可选项和参数是可以省略的。命令格式为:
Command [Options] Argument1……
其中:
Command:表示命令名称。在Linux系统内Shell命令严格区分大小写
Options:表示可选项。用于改变命令执行的动作类型,使用"-"引导,可以同时带有几个选项
Argument:表示参数列表。指出命令所作用的目标,有些命令允许携带不止一个参数
一条命令的三个要素需要使用空格分隔。若多个命令在一行内,则使用;将各个命令分隔。
可以在输入命令名或文件名的时候按Tab键进行自动补齐,若按两下Tab键则会查看所有带有该前缀的命令或文件。
若想查看之前执行过的命令,可以按上/下箭头键查看曾执行过的命令。除此之外,还可以输入history命令查看之前输入过的命令的历史记录。history命令默认为500条(即最近执行过的500条命令)(某些Linux系统为1000条)。
练习:说出以下命令的信息:
1.ifconfig
2.ping 192.168.1.1
3.gcc -v
4.ls -l /bin
3、通配符
当我们需要使用Shell命令(也叫Linux命令)处理一组文件(例如file1.txt、file2.txt、file3.txt……),按个输入文件名会十分的麻烦。这时我们可以使用通配符。
Shell命令的通配符有以下几种:
*(星号):匹配多个字符
?(问号):匹配一个字符
[](方括号):匹配指定的字符
[-](方括号内有-):匹配指定范围的字符
[^](方括号内有^):匹配除了指定字符外的字符
例如,现在有以下几个文件:
file1.txt
file2.txt
file3.txt
file123.txt
file124.txt
file134.txt
file125.txt
file5.txt
则以下通配符表示:
file?.txt:选中了文件file1.txt、file2.txt、file3.txt、file5.txt
file1?4.txt:选中了文件file124.txt和file134.txt
file*.txt:选中了所有文件
file1*.txt:选中了文件file1.txt、file123.txt、file124.txt、file134.txt、file125.txt
file[1-3].txt:选中了文件file1.txt、file2.txt、file3.txt
file[135].txt:选中了文件file1.txt、file3.txt、file5.txt
file[^135].txt:选中了文件file2.txt
4、管道
管道符号"|"可以将一系列的Shell命令连接起来,将第一个命令的输出作为第二个命令的输入,而第二个命令的输出又将作为第三个命令的输入……以此类推。管道经常与cut命令、grep命令等命令一起出现。
注意:“使用管道符号连接的两个命令”与上文的“使用;分隔多个命令”是有区别的。使用管道符号连接的命令有上下文关系(即上一个命令的输出作为下一个命令的输入),而使用;分隔多个命令并同时执行没有上下文关系。
例如,使用管道连接两个指令:
ls ~ | wc -w
wc 指令可以统计当前文档的相关信息,-w表示统计有多少词,-l表示有多少行,-m表示有多少字符。在这个用管道连接的命令中,ls ~的输出结果将作为wc -w的输入,wc命令统计ls ~命令输出的结果内有多少个单词。
通过管道符号"|"可以将多个Shell命令联合使用,可以实现单个指令中无法得到的效果。
示例1:命令 last | grep linux
last命令的意思是输出最近登录系统的用户信息;grep命令的意思是输出含有某关键字的行。该命令首先使用last命令获得登录用户信息,再通过grep命令查找有“linux”字样的记录。
grep指令可以解析输出文字并输出所有含有关键字的行。若想反向选择输出,则可以使用-v来指定不输出含有该关键字的行。例如:
last | grep -v wtmp
则不会输出带有关键字wtmp的行
示例2:命令 cat hello.c | grep printf
cat命令的意思是在终端打印指定文档。该命令首先将hello.c的内容输出,然后使用grep命令查找所有带有“printf”字样的行。
示例3:命令 echo $PATH | cut -d ':' -f 5
echo命令的意思是在终端输出指定字符串,$PATH表示Shell的PATH变量(指示Shell寻找命令的路径);cut命令可以以某个字符为分隔符剪切一个字符串成为若干个片段,其中-d后面指定了分隔符,-f后面指定了输出分隔后的第几个片段。该命令首先将$PATH变量输出,然后使用cut命令将这个变量值分隔为若干个小片段,然后输出第5段。
可以在-f后面跟若干个不同的数值用来输出指定的几个片段,数值间用逗号分隔;也可使用m-n来指定输出从m到n的片段,若未指定n的值则表示输出从m开始到结尾的所有片段。
练习:使用管道符号"|"连接合适的Shell命令,完成以下练习:
1.以'/'作为分隔符,分隔echo $HOME命令,并输出第2个及以后的片段
2.统计/etc/bash.bashrc这个文件内有多少个单词
3.输出某个.c文件内所有带有"printf"单词的行
4.使用ifconfig命令与grep命令,找出该计算机的ip地址(ip地址总会以192开头)
5.使用last命令、grep命令和wc命令,统计最近有几个用户曾登陆该计算机
答案:
1.echo $HOME | cut -d '/' -f 2-
2.cat /etc/bash.bashrc | wc -w
3.cat hello.c | grep printf
4.ifconfig | grep 192
5.last | grep [a-zA-Z] | grep -v wtmp | wc -l
5、输入输出重定向
在Linux中默认的输入是键盘,默认的输出是终端。若想改变输入/输出的目标,则需要使用输入输出重定向符号来改变输入输出目标重定向到新的目标。
输入输出重定向符号有以下几种:
> 文件名 或 1> 文件名:将该文件作为重定向的输出源,即将输出结果显示在该文件内。(采用w(新建)模式)
>> 文件名:将该文件作为重定向的输出源,即将输出结果显示在该文件内。(采用a(追加)模式)
< 文件名:将该文件作为重定向的输入源
2> 文件名 或 &> 文件名:将该文件作为重定向的输出错误源,即命令产生的错误信息会重定向到该文件中
示例1:ls -l > hello.txt 将ls -l的结果输出到文件hello.txt中
示例2:wc -l < hello.txt 将hello.txt作为输入内容传输给wc命令
练习:不使用cp命令,复制一个.c文件的内容
答案:cat hello.c > hello.txt 将hello.c的内容输出到文件hello.txt中
三、常用Shell命令
1、ls:列出当前目录下文件
-l:使用长格式显示详细属性
2、cat:将文本文件输出到终端
3、less/more:分屏显示文件
4、rm:删除文件
-r:删除目录及目录内文件
5、cp:复制文件
6、mv:移动文件 或 重命名文件
7、mkdir:创建目录
-p:多级创建
8、rmdir:删除空目录
9、cd:更改目录
10、grep:显示含有关键字的行
-v:反向选择(即不显示含有关键字的行)
11、head:显示文件开头
12、tail:显示文件结尾
13、sort:将文件内容排序后输出
-r:反序
-R:随机顺序
14、uniq:省略文件中相邻的重复行
-c:统计重复行的出现次数
-d:报告出现的重复行
-u:只会输出未重复的行
15、diff:比较两个文件。若两个都为文本文件则会输出两个文件不同的文本,若无差异则不会输出;若两个都为目录则会输出两个目录内文件的差异。diff命令通常用于查看两个补丁文件的异同从而进行软件的版本控制工作。
-w:忽略空格与制表符,将所有的空格视为一致。例如if(a == b)和if(a==b)将会视为一致。
16、file:判定文件类型
17、echo:显示文本
-n:输出文字不换行
-e:开启转义字符(可以使用\t(水平制表符)、\v(垂直制表符)、\n(换行符)等转义字符)
注意:若想让echo原样输出,则需要加上引号,否则echo会将每个用空格隔开的单词作为一个字符串,各字符串用空格分隔。例如:
1.echo "Hello World" 将间距较大的空格原样输出,输出Hello World
2.echo Hello World 认为输入的是两个单词,每个字符串用一个空格分隔,输出Hello World
18、date:显示/设置系统时间与日期
-d 字符串:显示指定字符串的时间而不是“现在时间”
-R:以RFC2822格式输出
-s 时间:设定指定的时间。通常我们使用"sudo date -s 时间"命令来设置当前系统时间
-u:输出协调世界时(Coordinated Universal Time,又称世界标准时间,简称UTC。中国大陆地区(上海)、中国香港、中国澳门、中国台湾与UTC时差为8小时,即中国大陆地区(上海)、中国香港、中国澳门、中国台湾记为UTC+8)
19、tar:归档文件/展开归档文件
20、whereis:查看命令存储位置/源码存储位置/帮助文档存储位置
-b:只显示命令存储位置
-s:只显示源码存储位置
-m:只显示帮助文档存储位置
21、which:定位某个命令的存储位置
22、ps:报告当前进程信息
-A或-e:报告所有进程
a:显示现行终端下的所有程序(包括其他用户)
x:不区分终端,显示所有程序
u:使用用户为主的格式
f:用树形结构显示
常用ps axu来显示所有进程信息,再配合grep和管道去查看特定进程信息。
使用ps显示进程信息,显示出的信息的表头信息分别为:
USER:进程所有者
PID:进程id号
PPID:父进程id号
PGID:进程组id号
SID:会话id号
TTY:进程相关的终端
CPU:占用CPU百分比
MEM:占用内存百分比
STAT:进程状态。有以下几种形式:
S:休眠
D:无法中断的休眠(例如某些负责IO的进程)
R:运行中
T:停止
Z:僵死
<:优先级高
N:优先级低
s:进程领导者,在该进程下有子进程
l:多进程的
+:后台进程组
TIME:进程消耗CPU的时间
COMMAND:命令行参数
23、top:实时监视当前进程
-p PID:监视指定进程号的进程。可以有多个PID
与ps命令不同,top命令显示的进程信息会进行实时刷新,通常通过top命令得出当前的CPU和内存负载情况。
24、df:报告文件系统占用空间情况
-a:显示全部文件系统
-h:方便阅读模式(即转换为1G=1024M,1M=1024K的模式)
-i:显示inode信息
-t 文件系统类型:只显示选定文件系统
25、du:显示磁盘空间的使用情况(内存的大小是4的倍数)
-h:方便阅读模式(即转换为1G=1024M,1M=1024K的模式)
-a:显示目录以及目录下其他子目录和子文件占用磁盘空间大小
-s:只显示目录,不显示目录下其他子目录和子文件占用磁盘空间大小
26、kill:杀死指定进程(需指定进程ID)
-9:强行杀死
-HUP 进程名:改为指定进程名
kill命令经常与ps命令一起使用,用于杀死已经死锁或需要终止的进程。
//实际上,kill命令的真正含义是向进程发送一个信号。有关kill的用法将会在进程间通信的课程中详细学习
27、chmod:改变文件的文件权限
用法:chmod 文件权限码 文件名。例如chmod 0775 hello.c
28、chown:改变文件所有者或文件组
用法:chown 用户名:组名 文件名。例如chown root:root hello.c
29、pwd:显示当前的绝对路径
30、ln:创建文件的链接(inode的执行命令)
-s:创建符号链接(软链接)。若此选项缺省则认为创建的是硬链接。
31、who:显示目前登陆系统的用户信息
who am i 或 -m:显示当前用户名
-H:显示表头信息
32、man;获取命令或程序的说明文档
对于同一个命令或程序,man命令可能拥有多个章节。这时我们可以在man命令后面添加对应的数字信息来查看更多信息。例如,输入man 1 printf和man 3 printf可以得到printf在不同章节的说明文档。
1:Shell标准命令说明
2:系统调用说明
3:常用库函数说明(一般为C库函数)
4:特殊文件说明(一般为/dev下的设备)
5:文件格式说明(例如/etc/passwd)
6:游戏
7:杂项
8:管理员指令
9:Linux特定的内核文档
在帮助文档内按q退出
-k:按关键字搜索说明文档。例如man -k "list directory"。注意list directory有无引号的区别。
33、shutdown:关闭/重启系统。一般需要超级用户权限。shutdown命令的一般用法是:
shutdown [可选项] [时间格式] [提示信息]
-r:重启
-h:关机
-k:不会真正关机,只是提示登录用户
-c:取消一个正在执行的shutdown命令
时间格式一般是'+'和数字,表示几分钟后。若想“立即”则可以指定为now
34、passwd:修改密码。出于安全性的考虑,Linux系统的密码是“不回显”的(即输入时不会显示位的个数)。root用户可以修改所有用户的密码,而普通用户只能修改自己的密码。
用法:passwd 用户名。修改某个用户名的密码
35、su:临时改变当前用户的身份。若未指定用户名则默认将当前用户改变为root用户。当需要退出该身份的时候,可以输入exit退出root用户。
36、clear:清空终端
四、Linux用户管理
Linux是一个多用户的操作系统,因此Linux系统的一个重要的工作就是对每个用户以及用户所有文件进行管理。
1、用户信息管理文件
每一个用户都具有以下的属性:
-用户名
-密码
-用户的ID(UID)
-用户主目录位置(HOME,即~的绝对路径)
-用户的Shell
在Linux内,用户信息主要由/etc/passwd和/etc/group两个文件管理。
/etc/passwd文件用来存储操作系统能够识别用户的信息清单。每一个用户都会在这个文件内有一条注册信息,当用户登陆的时候,系统从该文件中读取用户的UID和密码并进行验证。
在/etc/passwd文件内存储的用户信息有:
-登录名
-密码(不过是加密字符,不予显示)
-UID
-默认的组ID(GID)
-个人信息
-主目录所在路径
-登陆的Shell
每个信息使用冒号:分隔。例如:
linux:x:1000:1000:linux,,,:/home/linux:/bin/bash
登录名:linux
密码:x(加密字符,不予显示)
UID:1000
GID:1000
个人信息:linux
主目录所在路径:/home/linux
登陆的Shell:/bin/bash
/etc/group文件用来存储系统内用户组的信息,包括组名、GID、组成员列表
-组名
-密码(不过是加密字符,不予显示)
-GID
-成员列表,每个成员用逗号隔开
2、在系统内创建一个新用户
1)添加新用户
使用命令adduser来添加一个新用户。注意adduser命令只能root用户使用,因此需要切换成root用户来执行以下操作。
adduser liyuge
在执行命令后,Linux系统会提示用户输入密码、全名、电话、信息等,除了密码必须输入,其他信息可以按ENTER跳过输入。
adduser命令会自动为用户执行以下操作:
root@ubuntu:~# adduser liyuge
Adding user `liyuge' ...
Adding new group `liyuge' (1001) ...
Adding new user `liyuge' (1001) with group `liyuge' ...
Creating home directory `/home/liyuge' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
分别为:
1.添加新用户,用户名liyuge
2.创建新的用户组liyuge
3.将liyuge添加到组liyuge内
4.创建工作目录/home/liyuge
5.从/etc/skel内复制文件
6.等待用户输入密码
其中第五步的/etc/skel目录内存放的是一个普通用户的配置文件,常见的有.bashrc、.inputrc、.vimrc等配置文件。
在执行完adduser命令后,我们可以分别查看/etc/passwd文件和/etc/group文件的存储信息。
若想修改密码,可以使用passwd命令。
创建新用户成功后,可以使用su命令切换成新用户。
2)修改新用户属性
若想修改新用户的属性,则可以使用usermod命令。
usermod [可选项] 用户名
-d 目录名:更改该用户的工作目录地址。若后面有-m则表示旧目录会迁移至新目录,若新目录不存在则会创建。
-e 日期:指定该用户的账号有效截止日期,时间格式为MM/DD/YY。
-G 组名1,组名2……:指定该用户是以下组的成员(即加入这些组内),组名间用逗号分隔
-l 名称:更改该用户的登录名
-u 数值:更改该用户的UID,新指定的UID必须是一个唯一的值(即不能与已有UID同名)
-s shell目录:更改该用户默认shell,若后面的值缺省则会指定为系统默认的shell
注意:usermod命令无法更改正在线上的用户
例如将新用户添加进linux的组中:
usermod liyuge -G linux
这样我们就将用户linux和liyuge都划入linux组中。用户liyuge可以根据用户linux的组权限来访问文件。
3)删除用户
使用deluser来删除一个用户
使用delgroup来删除一个用户组
/****************************终端配置文件*************************/
Shell在运行时需要一定的配置文件才能正确有效的执行。Shell的配置文件主要有profile文件和bashrc文件。
1)/etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行
2)~/.profile:此文件为当前用户设置的自定义环境信息
3)/etc/bash.bashrc:此文件为系统的每个用户配置bash Shell的相关信息
4)~/.bashrc:此文件为当前用户配置自定义的bash Shell的相关信息
/****************************终端配置文件end**********************/