《Linux命令行与shell脚本大全》笔记
初识Linux Shell什么是LinuxLinux可划分为以下四部分:Linux内核GNU工具图形化桌面环境应用软件深入探究Linux内核内核主要负责以下四种功能:系统内存管理软件程序管理硬件设备管理文件系统管理系统内存管理不公管理服务器上的可用物理内存,还可以创建和不容易理虚拟内存。内核通过硬盘上的存储空间来实现虚拟内存,这块区域称为交换空间(swap s...
初识Linux Shell
什么是Linux
Linux可划分为以下四部分:
- Linux内核
- GNU工具
- 图形化桌面环境
- 应用软件
深入探究Linux内核
内核主要负责以下四种功能:
- 系统内存管理
- 软件程序管理
- 硬件设备管理
- 文件系统管理
系统内存管理
不公管理服务器上的可用物理内存,还可以创建和不容易理虚拟内存。
内核通过硬盘上的存储空间来实现虚拟内存,这块区域称为交换空间(swap space)。
内丰存储单元按组划分成很多块,这些块称作页面(page)。内核将每个存在 页面放在物理内存或交换空间。然后, 内核 会维护一个内存页面表。指明哪些页面位于物理内存内,哪些页面被换到硬盘上。
内核会记录哪些内存页面正在使用中,并自动把一段时间未访问的内存页面复制 到交换空间区域(称为换出,swapping out_)即使不宜可用内存。当程序要访问一个已被换出的内存页面时,内核必需从物理内存换出另外一个内存页面给它让出空间,然后从交换空间换入请求的内存页面。显然,这个过程 要花时间,拖慢运行的进程。只要Linux系统在运行,为运行中的程序换出内存面对面的的过程 就不会停歇。
软件程序管理
Linux操作系统将运行中的程序称为进程。可分为前台运行和后台运行。内核控制着Linux系统管理运行在系统上的所有进程。
内核创建了第一个进程(称为init进程)来启动系统上所有的其他进程。当内核启动时,它会将init进程加载到虚拟 内存中。内核 在启动任何其他进程时,都 会在虚拟 内存中给新进程分配 一块发你的区域 来存储该 进程用到的数据和代码。
一些Linux发行版使用一个表来管理在系统开机时要自动 启动的进程。在Linux系统上,这个表通常位于专门文件/etc/inittab中。有的系统(如Ubuntu)则采用/etc/init.d目录将开机时启动或停止某个应用的脚本 放在之个目录 下。这些脚本通过/etc/rcX.d目录下的入口 启动。X代表运行级别。
运行级别:
1.单用户
3.标准启动
5.X Windows
6.重启
硬件设备管理
内核的另一职责 是管理硬件设备。
任何Linux系统需要 与之通信的设备,都需要在内核 代码 中加入其驱动程序 代码。程序 代码相当 于应用程序 和硬件设备的中间人,允许内核 与设备之间交换数据。在Linux内核 中有两种方法用于插入设备驱动代码:
- 编译进内核 的设备驱动 代码
- 可插入内核 的设备驱动 模块
Linxu系统将硬件设备当成特殊 的文件,称为设备文件,设备文件有3种分类:
-
字符型 设备谁的
指处理数据时每次只能处理一个字符 的设备。大多数类型的调制解调器和终端都是作为字符型设备文件创建 的。
-
块设备文件
块设备是指处理数据时每次能处理大块数据 的设备,比如硬盘。
-
网络设备文件
是指采用数据包发送和接收数据 的设备,包括各种网卡和一个特殊 的回环设备。
Linux为系统上的每个设备都创建 一种称为节点的特殊文件。与设备的所有通信都 通过设备节点完成。每个节点都 有唯一 的数值 对供Linux内核 标识 它。数值 对包括一个主设备号和一个次设备号。类似的设备被划分到同样的主设备号下。次设备号用于标识 主设备组下的某个特定设备。
文件系统管理
不同于其他一些操作系统,Linux内核 支持通过不同类型的文件系统从硬盘中读写数据。如下列出了Linux系统用来读写数据的标准的文件系统。
文件系统 | 描述 |
---|---|
ext | Linux扩展文件系统,最早的Linux文件系统 |
ext2 | 第二扩展文件系统,在ext的基础上提供了更多 的功能 |
ext3 | 第三扩展文件系统,支持日志功能 |
ext4 | 第四扩展文件系统,支持高级日志功能 |
hgfs | OS/2高性能文件系统 |
ISO9660 | ISO 9660文件系统(CD-ROM) |
minix | minix文件系统 |
msdos | 微软的FAT16 |
ncp | Netware文件系统 |
nfs | 网络文件系统 |
ntfs | 支持Microsoft NT文件系统 |
proc | 访问系统信息 |
ReiserFS | 高级Linux文件系统,能提供性能和硬盘恢复功能 |
smb | 支持网络访问的Samba SMB文件系统 |
sysv | 软早期的Unix文件系统 |
ufs | BSD文件系统 |
umsdos | 建立在msdos上的类Unix文件系统 |
vfat | Windows95文件系统(FAT32) |
XFS | 高性能 64位日志文件系统 |
GNU工具
GNU是GNU’s Not Unix的缩写。
GNU组织开发了一套完整的Unix工具。
核心GNU工具
被称为coreutils软件包,它由三部分构成:
- 用以处理文件的工具
- 用以操作文本的工具
- 用以管理进程的工具
shell
GNU/Linux shell 是一种特殊的交互式工具。它为用户提供了启动程序,管理文件系统中的谇反及运行在Linux系统上的进程的途径。shell的核心是命令行提示符。命令行提示符是shell负责交互 的部分。它允许你输入 文本命令,然后解释 命令,并在内核中执行。
你也可以将多个shell命令放入文件中作为程序执行。这些文件被称作shell脚本。
在Linux,通常有好几中Linux shell可用。不同的shell有不同的特性,有些更利于创建脚本,有些则更利于管理进程。所有Linux发行版默认的shell都是bash shell。
shell | 描述 |
---|---|
ash | 一种运行在内存受限环境中简单轻量的shell,但与bash shell完全兼容。 |
korn | 一种与Bourne shell兼容的编程shell,但关联数组和浮点运算待一些高级的编程特性。 |
tcsh | 一种将C语言中的一些元素引入 到shell脚本 中的shell |
zsh | 一种结合 了bash,tcsh和korn的特性,同时提供高级编程特性,共享 历史 文件和主题化提示符的高级shell |
Linux桌面环境
X Window系统
KDE桌面
GNOME桌面
Unity桌面
其他桌面
- Fluxbox
- Xfce
- JWM
- Fvwm
- fvwm95
Linux发行版
不同的Linux发行版通常归类为3种:
- 完整的核心Linux发行版
- 特定用途的Linux发行版
- LiveCD测试发行版
核心Linux发行版
发行版 | 描述 |
---|---|
Slackware | 最早的LInux发行版中的一员,在Linux极客中比较流行 |
Red Hat | 主要用于Internet服务器商业发行版 |
Fedora | 从Red Hat分享出的家用发行版 |
Gentoo | 为高级Linux用户设计 的发行版,公包含linux源代码 |
openSUSE | 用于商用和家用的发行版 |
Debian | 在Linux专家和商用 linux产品中流行的发行版 |
特定用途的Linux发行版
- CentOD
- Ubuntu
- PCLinuxOS
- Mint
- dyne:bolic
- Puppy Linux
- …
Linux LiveCD
走进Shell
进入命令行
控制台终端
图形化终端
通过Linux控制台终端访问CLI
在大多数Linux发行版中,你可以使用简单按键组合访问某个Linux虚拟控制台。通常必须按下Ctrl + Alt组合键,然后按功能键F1 - F7进入要使用的虚拟控制台。
可以将终端的背景色设置成白色,其中一种方法是
setterm -inversescreen on
或
setterm -background white
setterm -foreground black
共有八种颜色可供选择,分别是black, red, green, yeallow, blue, magenta, cyan, white
选项 | 参数 | 描述 |
---|---|---|
-background | black, red, green, yellow, blue, magenta, cyan, white | 将终端的背景色改为指定颜色 |
-foreground | black, red, green, yellow, blue, magenta, cyan, white | 将终端的前景色改为指定颜色 |
-inversescreen | on或off | 交换背景色和前景色 |
-reset | 无 | 将终端外观恢复成默认设置并清屏 |
-store | 无 | 将终端当前的前景色和背景色设置成-reset选项的值 |
通过图形化终端仿真访问CLI
使用GNOME Terminal仿真器
使用Konsole Terminal仿真器
使用Xterm
基本Bash shell命令
启动Shell
shell提示符
默认bash shell提示符是美元符号($),这个符号表明shell在等待用户输入。
bash手册
大多数Linux发行版自带用以查找shell命令及其他GNU工具信息的在线手册 。
man命令用来访问存储在Linux系统上的手册的页面。
Linux手册页惯用的节名
节 | 描述 |
---|---|
Name | 显示命令名和一段简短的描述 |
Synopsis | 命令的语法 |
Configuration | 命令配置信息 |
Description | 命令的一般性描述 |
Options | 命令选项描述 |
Exit Status | 命令的退出状态指示 |
Return Value | 命令的返回值 |
Errors | 命令的错误的消息 |
Environment | 描述所使用的环境变量 |
Files | 命令用到的文件 |
Versions | 命令的版本信息 |
Conforming To | 命名所遵从的标准 |
Notes | 其他有帮助的资料 |
Bugs | 提供提交Bug的途径 |
Example | 展示命令的用法 |
Authors | 命令开以人员的信息 |
Copyright | 命令源代码 的版权状况 |
See Also | 与该 命令类型的其他命令 |
Linux手册页的内容区域
区域号 | 所涵盖的内容 |
---|---|
1 | 可执行程序或shell命令 |
2 | 系统调用 |
3 | 库调用 |
4 | 特殊文件 |
5 | 文件格式与约定 |
6 | 游戏 |
7 | 概览,约定及杂项 |
8 | 超级用户和系统管理员命令 |
9 | 内核例程 |
手册页不是唯一 的资料。还有另一种叫作info页面的信息。
另外大多数命令都可以接受-help或–help选项。
浏览文件系统
Linux文件系统
Linux路径本身并没有提供任何有关文件空间存放在哪个物理磁盘上的信息。
在Linux PC上安装的第一块硬盘称为根驱动器。根驱动器包含了虚拟目录的核心,其他目录都是从那里开始构建的。
常见Linux目录名称
目录 | 用途 |
---|---|
/ | 虚拟目录的根目录。通常不会在这里存储文件 |
/bin | 二进制目录,存放许多用户级的GNU工具 |
/boot | 启动目录,存放启动文件 |
/etc | 系统配置文件目录 |
/home | 主目录,Linux在这里创建用户的目录 |
/lib | 库目录,存放系统和应用程序的库文件 |
/media | 媒体目录,可移动媒体设备的常用挂载点 |
/mnt | 挂载目录,另一个可移动 媒体设备的常用挂载点 |
/opt | 可选目录,常用于存放第三方软件包和数据文件 |
/proc | 进程目录,存放现有硬件及当前相关信息 |
/root | root用户的主目录 |
/sbin | 系统二进程目录,存放许多GNU管理员级工具 |
/run | 运行目录,存放系统动作时的运行时数据 |
/srv | 服务目录,存放本地服务的相关文件 |
/sys | 系统目录,存放系统硬件信息的相关文件 |
/tmp | 临时目录,可以在该目录中创建和删除临时工作文件 |
/usr | 用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里 |
/var | 可变目录,用以存放经常变化的文件,比如日志文件 |
遍历目录
cd destination
- 绝对文件路径
绝对文件路径总是以正斜线作为起始,指明虚拟文件系统的根目录。
- 显示shell会话的当前目录
pwd
- 相对文件路径
相对文件路径允许用户指定一个基于当前位置的目录文件路径。
单点(.): 表示当前目录
双点(…):表示当前目录的父目录
文件和目录列表
基本列表功能
ls命令最基本的形式会显示当前目录下的文件和目录
参数:
-F: 可以轻松区分文件和目录,它会在目录后边加/,还会在可执行文件后边星号。
-a: 可以把隐藏文件和普通文件及目录一起显示出来。
-R: 递归选项
-l: 长列表格式输出
-i: 显示inode
会显示如下内容:
- 文件类型,比如目录(d),文件(-), 字符型文件(c)或块设备(b);
- 文件的权限
- 文件的硬链接总数
- 文件属主的用户名
- 文件属组的组名
- 文件的大小(以字节为单位)
- 文件的上次修改时间
- 文件名或目录名
-h: 以容易识别的文件大小显示
过滤输出列表
ls xxx
- ?: 代表一个字符
- *:代表零个或多个字符
处理文件
创建文件
touch filename
会创建一个空文件
如果只想改变文件的访问时间可以使用-a参数
touch -a filename
复制文件
cp source destination
参数:
-i: 重名需要确认
-R: 递归
制表键自动补全
链接文件
Linux中有两种不同类型的文件链接
- 符号链接
ls -s source lnFile
lnFile是指向source的一个新文件,可以通过inode编号查看
- 硬链接
硬链接会创建独立的虚拟文件,其中包含了原始文件的信息及位置。但是它们从根本上而言是同一个文件。引用硬链接文件等同于引用了源文件。要创建硬链接,原始文件也必须事先存在,只不过这次使用ln命令时不再需要加入额外的参数了。
重命名文件
mv命令,可以将目录移动到另一个位置或重新命名
mv source destination
或
mv oldfilename newfilename
删除文件
rm -i file
-i: 删除文件时需要确认一次才会删除
-f:强制删除文件
-r:级联删除文件夹
处理目录
创建目录
mkdir newDir
参数:
-p:创建多级目录
删除目录
rm -ri
查看文件内容
查看文件类型
file my_file
my_file: ASCII text
查看整个文件
-
cat
- -n: 显示行号
- -b: 只给有文本的行加上行号
- -T: 用^I替换制表符
-
more
以分页的形式显示文件内容
-
less
查看部分文件
-
tail
tail命令默认会显示文件最后10行内容
-n 2: 显示最后两行内容
-f: 使tail保持活动状态,并不断显示添加到文件中的内容
-
head
默认显示文件的前10行
head -num: 显示前num行内容
更多的Bash shell
监测程序
探查进程
默认ps只会显示运行在当前控制台下的属于当前用记的进程。
Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:
- Unix风格的参数,前面加单破折线
- BSD风格的参数,前面不加破折线
- GNU风格的长参数,前面加双破折线
Unix风格的ps命令参数
参数 | 描述 |
---|---|
-A | 显示所有进程 |
-N | 显示与指定参数不符的所有进程 |
-a | 显示除控制进程和无终端进程外的所有进程 |
-d | 显示除控制进程外的所有进程 |
-e | 显示所有进程 |
-C cmdlist | 显示包含在cmdlist列表中的进程 |
-G grplist | 显示组ID在grplist列表中的进程 |
-U userlist | 显示属主的用户ID在userlist列表中的进程 |
-g grplist | 显示会话或组ID在grplist列表 |
-p pidlist | 显示PID在pidlist列表中的进程 |
-s sesslist | 显示会话ID在sesslist列表中的进程 |
-t ttylist | 显示终端ID在ttylist列表中的进程 |
-u userlist | 显示有效用户iD在userlist列表中的进程 |
-F | 显示更多额外输出(相对于-f参数而言) |
-O format | 显示默认的输出列以及format列表指定的特定列 |
-M | 显示进程的安全信息 |
-c | 显示进程额外调试器信息 |
-f | 显示完整格式的输出 |
-j | 显示任务信息 |
-l | 显示长列表 |
-o format | 公显示由format指定的列 |
-y | 不要显示进程标记(process flag, 表明进程状态的标记) |
-Z | 显示安全标签(security context)信息 |
-H | 用层级格式来显示进程(树状,用来显示父进程) |
-n namelist | 定义了WCHAN列显示的值 |
-w | 采用宽输出模式,不限宽度显示 |
-L | 显示进程中的线程 |
-V | 显示ps命令的版本号 |
e.g.
ps -ef
显示内容:
- UID: 启动这些进程的用户
- PID: 进程的进程ID
- PPID: 父进程的进程号(如果该 进程是由另一个进程启动的)
- C: 进程生命周期中的CPU利用率
- STIME: 进程启动时的系统时间
- TTY: 进程启动时的终端设备
- TIME: 运行进程需要的累计CPU时间
- CMD: 启动的程序名称
-l参数:
多出的列:
- F: 内核分配给进程的系统标记
- S: 进程的状态(O代表正在运行;S代表在休眠;R代表可运行,正等待运行;Z代表僵化,进程已结束但父进程已不存在;T代表停止)
- PRI: 进程的优先级(越大的数字低的优先级)
- NI: 谦让度值 用来参与决定优先级
- ADDR: 进程的内存地址
- SZ: 假如进程被换出, 所需要交换空间的大致大小
- WCHAN: 进程休眠的内核函数的地址
BSD风格
主要命令参数:
参数 | 描述 |
---|---|
T | 显示跟当前终端关联的所有进程 |
a | 显示跟任意终端关联的所有进程 |
g | 显示所有的进程,包括控制进程 |
r | 仅显示运行中的进程 |
x | 显示所有的进程,甚至包括未分配任何终端的进程 |
U userlist | 显示归userlist列表中的某用户ID所有的进程 |
p pidlist | 显示PID在pidlist列表中的进程 |
t ttylist | 显示所关联的终端在ttylist列表中的进程 |
O format | 除了默认输出的列之外,还输出由format指定的列 |
X | 按过去的Linux i386寄存器格式显示 |
Z | 将安全信息添加到输出中 |
j | 显示任务信息 |
l | 采用长模式 |
o format | 公显示由format指定的列 |
s | 采用信号格式显示 |
u | 采用基于用户的格式显示 |
v | 采用虚拟内存格式显示 |
N namelist | 定义在WCHAN列中使用的值 |
O order | 定义显示信息列的顺序 |
S | 将数值信息从子进程加到父进程上,比如CPU和内存的使用情况 |
c | 显示真实的命令名称 (用以启动进程的程序名称) |
e | 显示命令使用的环境变量 |
f | 用分层格式来显示进程,表明哪些进程启动了哪些进程 |
h | 不显示头信息 |
k sort | 指定用以将输出排序的列 |
n | 和WCHAN信息一起显示出来,用数值来表示用户ID和组ID |
w | 为较宽屏幕显示宽输出 |
H | 将线程按进程来显示 |
m | 在进程后显示线程 |
L | 列出所有格式指定符 |
V | 显示ps命令的版本号 |
输出结果中的大部分的输出列跟使用Unix风格参数时的输出是一样的,只有一小部分如下:
-
VSZ: 进程在内存中的大小以KB为单位
-
RSS: 进程在未换出时占用的物理内存
-
STAT: 代表当前进程状态 的双字符状态码
-
第一个字符采用了和Unix风格S列相同的值,表明进程是在休眠,运行还是等待。
-
第二个参数进一步说明进程的状态
<: 该进程运行在高优先级上
N:该进程运行在低优先级上
L: 该进程有页面锁定在内存中
s: 该 进程是控制进程
l: 该进程是多线程的
+: 该进程运行在前台
-
GNU长参数
常用参数
参数 | 描述 |
---|---|
–deselect | 显示所有进程,命令行中列出的进程 |
–Group grplist | 显示组ID在grplist列表中的进程 |
–User userlist | 显示用户ID在userlist列表中的进程 |
–group grplist | 显示有效组ID在grplist列表中的进程 |
–pid pidlist | 显示PID在pidlist列表中的进程 |
–ppid pidlist | 显示父PID在pidlist列表中的进程 |
–sid sidlist | 显示会话ID在sidlist列表中的进程 |
–tty ttylist | 显示终端设备号在ttylist列表中的进程 |
–user userlist | 显示有效用户ID的userlist列表中的进程 |
–format format | 仅显示由format指定的列 |
–context | 显示额外的安全信息 |
–cols n | 将屏幕宽度设置为n列 |
–columns n | 将屏幕宽度设置为n列 |
–cumulative | 包含已停止的子进程的信息 |
–forest | 用层级结构显示出进程和父进程之间的关系 |
–headers | 在每页输出中都显示列的头 |
–no-headers | 不显示列的头 |
–lines n | 将屏幕高度设为n行 |
–rows n | 将屏幕高度设为n排 |
–sort order | 指定将输出按哪列排序 |
–width n | 将屏幕宽度设为N列 |
–help | 显示帮助信息 |
–info | 显示调试信息 |
–version | 显示ps命令的版本号 |
实时监测进程
top
输出的第一部分显示的是系统的概况:
第一行显示了当前时间,系统的运行时间,登录的用户数以及系统的平均负载。
平均负载有3个值,最近1分钟的,最近5分钟的和最近15分钟的平均负载。值越大说明系统的负载越高。
通常,如果系统的负载值超过2,就说明系统比较繁忙了。
第二行显示了进程概要信息–top命令的输出中将进程叫作任务(task):
有多少进程处在运行,休眠,停止或僵化状态
第三行显示了Cpu的概要信息。
紧跟其后的两行说明了系统内存的状态。
第一行是系统的物理内存: 总共有多少内存,当前使用了多少,还有多少空闲。后一行说的是同样的信息,不过是针对系统交换空间。
最后一部分显示了当前运行中的进程的详细列表。有些跟ps命令的输出类似。
- PID:进程的ID
- USER: 进程属主的名字
- PR: 进程的优先级
- NI: 进程的谦让度值
- VIRT: 进程占用的虚拟内存总量
- RES: 进程占用的物理内存总量
- SHR: 进程和其他进程共享 的内存总量
- S: 进程的状态(D代表可中断的休眠状态,R代表在运行状态,S代表休眠状态,T代表跟踪状态或停止状态,Z代表僵化状态)
- %CPU: 进程使用的CPU时间比例
- %MEM: 进程使用的内存占可用内存的比例
- TIME+: 自进程启动到目前为止的CPU时间总量
- COMMAND: 进程所对应的命令行名称,也就是启动的程序名。
默认top命令会对按昭%cpu值对进程排序。可以在top运行时使用多种交互命令重新排序。每个交互式命令都 是单字符,在top命令运行时键入可改变top的行为。键入f允许你选择对输出进行排序的字段,键入d允许你修改轮询间隔。键入q可以退出top。用户在top命令的输出上有很大的控制权。
结束进程
在Linux中进程之间通过信号来通信。
Linux进程信号:
信号 | 名称 | 描述 |
---|---|---|
1 | HUP | 挂起 |
2 | INT | 中断 |
3 | QUIT | 结束运行 |
9 | KILL | 无条件终止 |
11 | SEGV | 段错误 |
15 | TERM | 尽可能终止 |
17 | STOP | 无条件停止运行,但不终止 |
18 | TSTP | 停止或暂停,但继续在后台运行 |
19 | CONT | 在STOP或TSTP之后恢复执行 |
在Linux中有两个命令可以向运行中的进程发出进程信号
kill
kill -option pid pid pid…
killall
killall命令支持通过进程名而不是PID来结束进程。
killall也支持通配符。
e.g.
killall http* # 结束所有以http开头的进程
监测磁盘空间
挂载存储媒体
mount
默认情况下,mount命令会输出当前系统上挂载的设备列表
默认提供如下四部分信息:
- 媒体的设备文件名
- 媒体挂载到虚拟目录的挂载点
- 文件系统类型
- 已挂载媒体的访问状态
需要手动在虚拟目录中挂载设备,需要以root用户身价登录,或是以root用户身份运行sudo命令。
mount -t type device directory
如果Type是VindowsPC共用的存储设备,通常类型如下:
- vfat: Windows长文件系统
- ntfs: windows NT, XP, Vistra和Windows7中广泛使用的高级文件系统
- iso9660: 标准Cd-ROM文件系统
mount命令的参数
参数 | 描述 |
---|---|
-a | 挂载/etc/fstab文件中指定的所有文件系统 |
-f | 使用mount命令模拟挂载设备,但并不真的挂载 |
-F | 和-a参数一起使用时,会同时挂载所有文件系统 |
-v | 详细模式,将会说明挂载设备的每一步 |
-I | 不启用任何/sbin/mount.filesystem下的文件系统帮助文件 |
-l | 给ext2,ext3或XFS文件系统自动 添加文件系统标签 |
-n | 挂载设备,但不注册到/etc/mtab已挂载设备文件中 |
-p num | 进行加密挂载时,从文件描述符num中获得密码短语 |
-s | 忽略该文件系统不支持的挂载选项 |
-r | 将设备挂载为只读的 |
-w | 将设备挂载为可读写的(默认参数) |
-L label | 将设备按指定 的label挂载 |
-U uuid | 将设备按指定的uuid挂载 |
-O | 和-a参数一起使用,限制命令只作用到特定的一组文件系统上 |
-o | 给文件系统添加特定的选项 |
以下为-o常用参数
- ro: 以只读形式挂载
- rw: 以读写形式挂载
- user: 允许普通用户挂载文件系统
- check=none: 挂载文件系统时不进行完整校验
- loop: 挂载一个文件
umount
从Linux系统上移除一个可移动设备时,不能直接从系统上移除,而应该先卸载。
umount [directory | device]
df
用来查看所有已挂载磁盘的使用情况
命令输出格式:
- 设备的设备文件位置
- 能容纳多少个1024字节大小的块
- 已用了多少个1024字节大小的块
- 还有多少个1024字节大小的块可用
- 已用空间所占比例
- 设备挂载到了哪个挂载点上
常用参数:
- -h: 以可读的方式显示容量
du
此命令可以显示某个特定目录(默认情况下是当前目录)的磁盘使用情况
常用参数
- -c : 显示所有已列出文件总的大小
- -h: 按用户易读的格式输出大小
- -s: 显示每个输出参数的总计
- –max-depth=num: 只统计num深度的目录
处理数据文件
排序数据
sort
常用参数:
单破折线 | 双破折线 | 描述 |
---|---|---|
-b | –ignore-leading-blanks | 排序时忽略起始的空白 |
-C | –check-quiet | 不排序,如果数据无序也不要报告 |
-c | –check | 不排序,但检查输入数据是不是已排序;未排序的话,报告 |
-d | –dictionary-order | 仅考虑空白和字母,不考虑特殊字符 |
-f | –ignore-case | 默认情况下,会将大写字母排在前面;这个参数会忽略大小写 |
-g | –general-number-sort | 按通用数值来排序(跟-n不同,把值当浮点数来排序,支持科学计数法表示的值) |
-i | –ignore-nonprinting | 在排序时忽略不可打印字符 |
-k | –key=POST1 [, POS2] | 排序从POS1位置开始,如果指定了POS2的话,到POS2位置结束 |
-M | –month-sort | 用三个字符月份名按月份排序 |
-m | –mrege | 将两个已排序数据文件合并 |
-n | –numeric-sort | 按字符串数值来排序(并不转换为浮点数) |
-o | –output=file | 将排序结果写出到指定的文件中 |
-R | –random-sort --random-source=FILE | 按随机生成的散列表的键值排序。 指定 -R参数用到的随机字节的源文件 |
-r | –reverse | 反序排序 |
-S | –buffer-size=SIZE | 指定使用的内存大小 |
-s | –stable | 禁用最后重排序比较 |
-T | –temporary-directory=DIR | 指定一个位置来存储临时工作文件 |
-t | –field-separator=SEP | 指定一个用来区分键位置的字符 |
-u | –unique | 和-c参数一起使用时, 检查严格排序;不和-c参数一起使用时,公输出第一例相似的两行 |
-z | –zero-terminated | 用NULL字符作为行尾,而不是用换行符 |
搜索数据
grep
grep [option] pattern [file]
常用参数:
- -v: 输入不匹配该模式的行
- -n: 显示行号
- -c: 统计符合匹配的行数
- -e:多模式匹配,每个参数使用-e来标识
- parttern支持正则表达式
fgrep
压缩数据
Linux文件压缩工具
工具 | 文件扩展名 | 描述 |
---|---|---|
bzip2 | .bz2 | 采用Burrows-Wheeler块排序文本压缩算法和霍夫曼编码 |
compress | .Z | 最初的Unix文件压缩工具,已经快没人用了 |
gzip | .gz | GNU压缩工具,用Lempel-Ziv编码 |
zip | .zip | Windows上PKZIP工具的Unix实现 |
gzip
这个软件意在编写一个能够替代原先Unix中compress工具的免费版。它包含以下工具
- gzip: 用来压缩文件
- gzcat: 用来查看压缩过的文本文件的内容
- gunzip: 用来解压缩
归档数据
tar
tar function [options] object1 object2 …
function参数定义了tar命令应该做什么,如下:
功能 | 长名称 | 描述 |
---|---|---|
-A | –concatenate | 将一个已有的tar归档文件追加到另一个已有tar归档文件 |
-d | –create | 创建一个新的tar归档文件 |
-d | –diff | 检查归档文件和文件系统的不同之年 |
–delete | 从已有tar归档文件中删除 | |
-r | –append | 追加文件到已有tar归档文件末尾 |
-t | –list | 列出已有tar归档文件中的内容 |
-u | –update | 将比tar归档文件中已有的同名文件新的文件追加到该 tar归档文件中 |
-x | –extract | 从已有tar归档文件中提取文件 |
tar命令选项
选项 | 描述 |
---|---|
-C dir | 切换到指定目录 |
-f file | 输出结果到时文件或设备file |
-j | 将输出重定向给bzip2命令来压缩内容 |
-p | 保留所有文件权限 |
-v | 在处理文件时显示文件 |
-z | 将输出重定向给gzip命令来压缩内容 |
理解 Shell
shell的类型
系统启动什么样的shell程序取决于你个人的用户配置。在/etc/passwd文件中,在用记ID记录的第7个字段中列出了默认的shell程序。
shell的父子关系
bash shell程序可使用命令行参数修改shell启动方式。
常用参数:
参数 | 描述 |
---|---|
-c string | 从string中读取命令并进行处理 |
-i | 启动一个能够接收用户输入 的交互式shell |
-l | 以登录shell的形式启动 |
-r | 启动一个受限shell,用户会被限制在默认目录中 |
-s | 从标准输入中读取命令 |
进程列表
将所有命令写在一行并以分号分隔,最后使用圆括号括起所有命令。
(pwd; cd; ls; echo $BASH_SUBSHELL)
加入括号使命令列表变成了进程列表,生成了一个子shell来执行对应的命令。
进程列表是一种命令分组(command grouping)。另一种命令分组是将命令放入花括号中,并在命令列表尾部加上分号(;)。语法为{command; }。使用花括号进行命令分组并不会像进程列表那样创建出子shell.
别出心裁的子shell用法
探索后台模式
sleep
在后台模式中运行命令可以在处理命令的同时让出CLI,以供使用。
演示后台模式的一个经典命令就是sleep。
sleep接受一个cdvo,yynw参数是你希望进程等待的秒数。
sleep 10 &
想要将命令置入后台模式,可以在命令末尾加上字符&。
jobs
可以显示出当前运行在后台模式中的所有用户的进程。
参数:
- -l: 显示后台进程的PID
将进程列表置入后台
&
协程
协程可以同时做两件事。它在后台生成一个子shell,并在这个子shell中执行命令。
要进程协程处理,得使用coproc命令,还有要在子shell中执行的命令。
e.g.
coproc My_job { sleep 10; }
[1] 2570
jobs
[1]+ Running coproc My_job { sleep 10; } &
理解shell的内建命令
外部命令
外部命令,有时候也被称为文件系统命令,是存在于bash shell之外的程序。它们并不是sheel程序的一部分。外部命令程序通常位于/bin,/usr/bin,/sbin或者/usr/bin中。
我们可以使用which和type命令找到它们。
当外部命令执行时,会创建一个子进程。这种操作被称为衍生(forking)。
内建命令
内建命令与外部命令的区别在于前都不需要使用子进程来执行。它们已经和shell编译成了一体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行。
因为不既不需要通过衍生出子进程来执行,也不需要打开程序文件,内建命令的执行速度要更快,效率也高。
history
可以查看最近用过的命令列表,通常历史记录中会保存最近的1000条命令。你也可以修改这个数字,你需要修改名为HISTSIZE的环境变量。
- history -a: 可以将命令历史强制写入.bash_history文件。
命令别名
alias命令是另一个shell的内建命令。它允许你为常用的命令及其参数创建另一个名称,从而将输入量减少到最低。
很多Linux发行版很有可能已经为你设置好了一些常用命令的别名。可以使用alias -p查看。
使用Linux环境变量
Linux环境变量能帮你提升Linux shell体验。很多程序和脚本都通过环境变量来获取系统信息、存储临时数据和配置信息。
什么是环境变量
在bash shell中,环境变量分为两类:
- 全局变量
- 局部变量
全局环境变量
全局环境变量对于shell会话和所有生成的子shell都是可见的。局部变量则只对创建他们的shell可见。
查看全局变量,可以使用env或printenv命令。
要显示个别环境变量的值,可以使用printenv命令。
printenv HOME
也可以使用echo $环境变量名
echo $HOME
局部环境变量
局部变量只能在定义它们的进程中可见。
在Linux系统中没有一个只显示局部环境变量的命令。
set命令会显示为某个特定进程设置的所有环境变量,包括局部变量,全局变量以及用户定义变量。
设置用户定义变量
可以在bash shell中直接设置自己的变量。
设置局部用户定义变量
我们可以通过等号给环境变量赋值,值可以是数值或字符串。
my_variable=Hello
echo $my_variable
如果要给变量赋一个含有空格的字符串值,必须用单引号来界定字符串的首和尾。
变量名,等号和值之间不能有空格。
设置全局环境变量
方法是:先创建一个局部环境变量,然后再把它导出到全局环境中。
使用export命令完成命令导出到全局环境,变量名前不需要加$.
删除环境变量
unset
注意: 在涉及环境变量名时,如果要用到变量,使用 ; 如 果 要 操 作 变 量 , 不 加 ;如果要操作变量,不加 ;如果要操作变量,不加。这条规则的一个例外就是使用printenv显示某个变量的值。
默认的shell环境变量
bash shell支持的Bourne变量
变量 | 描述 |
---|---|
CDPATH | 冒号分隔的目录列表, 作为cd命令的搜索路径 |
HOME | 当前用户的主目录 |
IFS | shell用来将文本字符串分割成字段的一系列字符 |
当前用户收件箱的文件名 | |
MAILPATH | 冒号分隔当前用户收件箱的文件名列表 |
OPTARG | getopts命令处理的最后一个选项参数值 |
OPTIND | getopts命令处理的最后一个参数的索引号 |
PATH | shell查找命令的目录列表,由冒号分隔 |
PS1 | shell命令行界面的主提示符 |
PS2 | shell命令行界面的次提示 |
bash shell环境变量
变量 | 描述 |
---|---|
BASH | 当前shell实例的全路径名 |
BASH_ALIASES | 含有当前已设置别名的关联数组 |
BASH_ARGC | 含有传入子函数或shell脚本 的参数总数的数组变量 |
BASH_ARCV | 含有传入子函数或shell脚本的参数的数组变量 |
BASH_CMDS | 关联数组,包含shell执行过的命令的所有位置 |
BASH_COMMAND | shell正在执行的命令或马上就执行的命令 |
BASH_ENV | 设置了的话,每个bash脚本会在运行前先尝试运行该 变量定义的启动文件 |
BASH_EXECUTION_STRING | 使用bash -c选项传递过来的命令 |
BASH_LINENO | 含有当前执行的shell函数的源代码秸的数组变量 |
BASH_REMATCH | 只读数组,在使用正则表达式的比较运算符=~进行肯定匹配(positive math)时,包含了匹配到的模式和子模式 |
BASH_SOURCE | 含有当前正在 执行的shell函数所在源文件名的数组变量 |
BASH_SUBSHELL | 当前子shell环境的嵌套级别(初始是0) |
BASH_VERSINFO | 含有当前运行的bash shell的主版本号和次版本号和数组变量 |
BASH_VERSION | 当前运行的bash shell的版本号 |
BASH_XTRACEFD | 若设置成了有效的文件描述符(0,1,2),则’set -x’调试选项生成的跟踪输出可被重定向。通常用来将跟踪输出到一个文件中 |
BASHOPTS | 当前启动的bash shell选项的列表 |
BASHPID | 当前bash进程的PID |
COLUMNS | 当前bash shell实例所有终端的宽度 |
COMP_CWORD | COMP_WORDS变量的索引值,后者含有当前光标的位置 |
COMP_LINE | 当前命令行 |
COMP_POINT | 当前光标位置相对于当前命令起始索引 |
COMP_KEY | 用来调用shell函数补全功能 的最后一个键 |
COMP_TYPE | 一个整数值,表示所尝试的补全类型,用以完成shell函数补全。 |
COMP_WORDBREAKS | Readline库中用于单词补全的词分隔字符 |
COMP_WORDS | 含有当前命令行所有单词的数组变量 |
COMPREPLY | 含有由shell函数生成的可能填充代码的数组变量 |
COPROC | 占用未命名的协进程的I/O文件描述 符的数组变量 |
DIRSTACK | 含有目录栈当前内容的数组变量 |
EMACS | 设置为‘t’时,表明emacs shell缓冲区正在工作,而行编辑功能被禁止 |
ENV | 如果设置了该 环境变量,在bash shell脚本 运行之前会先执行已定义的启动文件(仅用于当bash shell以POSIX模式被调用时) |
EUID | 当前用户的有效用户ID(数字形式) |
FCEDIT | 供fc命令使用的默认编辑器 |
FIGNORE | 在进行文件名补全时可以忽略后缀名列表,由冒号分隔 |
FUNCANME | 当前执行的shell函数名称 |
FUNCNEST | 当设置成非零时,表示所允许的最大函数嵌套级数(一旦超出,当前命令即被终止) |
GLOBIGNORE | 冒号分隔的模式列表,定义了在进行文件名扩展时可以忽略的一组文件名 |
GOUPS | 含有当前用户属组列表的数组变量 |
HISTCHARS | 控制历史记录扩展,最多可有3个字符 |
HISTCMD | 当前命令在历史记录中的编号 |
HISTCONTROL | 控制哪些命令留在历史记录列表中 |
HISTFILE | 保存shell历史记录列表 的文件名(默认是.bash_hisotry) |
HISTFILESIZE | 最多在历史文件中存多少行 |
HISTTIMEFORMAT | 如果设置了且非空,就用作格式化字符串,以显示bash历史中每条命令的时间戳 |
HISTIGNORE | 同冒号分隔的模式列表,同用来决定 历史文件中哪些命令会被忽略 |
HISTSIZE | 最多在历史文件中存多少条命令 |
HISTFILE | shell在补全主机名时读取的文件名 |
HOSTNAME | 当前主机的名称 |
HOSTTYPE | 当前运行bash shell的机器 |
IGNOREEOF | shell在退出前必须收到连续的EOF字符的数量(如果这个值不存在,默认是1) |
INPUTRC | Readline初始化文件名(默认是.inputrc) |
LANG | shell的语言环境类别 |
LC_ALL | 定义了一个语言环境类别,能够覆盖LANG变量 |
LC_COLLATE | 设置对字符串排序时用的排序规则 |
LC_CTYPE | 决定如何解释出现在文件名扩展和模式匹配中的字符 |
LC_MESSAGES | 在解释前面带有$的双引号字符串时,该环境变量决定了所采用的语言环境设置 |
LC_NUMERIC | 决定着格式化数字时采用的语言环境设置 |
LINENO | 当前执行的脚本 的行号 |
LINES | 定义了终端上可见的行数 |
MACHTYPE | 用“CPU-公司-系统”(Cpu-company-system)格式定义的系统类型 |
MAPFILE | 一个数组变量,当mapfile命令未指定数组变量作为参数时, 它存储了mapfile所讲稿的文本 |
MAILCHECK | shell查看新邮件的频率 (以秒为单位,默认是60) |
OLDPWD | shell之前的工作目录 |
OPTERR | 设置为1时,bash shell会显示getopts命令产生的错误 |
OSTYPE | 定义了shell所在的操作系统 |
PIPESTATUS | 含有前台进程的能出状态列表 的数组变量 |
POSIXLY_CORRECT | 设置了的话,bash会以POSIX模式启动 |
PPID | bash shell父进程的PID |
PROMPT_COMMAND | 设置了的话,在命令行主提示符显示之前会执行这条命令 |
PROMPT_DIRTRIM | 用来定义当启用了\w或\W提示符字符串转义时显示的尾部目录名的数量。被删除的目录名会用一组英文句点替换 |
PS3 | select命令的提示符 |
PS4 | 如果使用了bash的-x选项,在命令行之前显示的提示信息 |
PWD | 当前工作目录 |
RANDOM | 返回一个0~32767的随机数(对其的赋值可作为随机数生成器的种子) |
READLINE_LINE | 当使用bind -x命令时,存储Readline缓冲区的内容 |
READLINE_POINT | 当使用bind -x命令时,表示 Readline缓冲区内容插入点的当前位置 |
REPLY | read命令的默认变量 |
SECONDS | 自从shell启动到现在的秒数(对其赋值将重置计数器) |
SHELL | bash shell的全路径名 |
SHELLOPTS | 已启用bash shell选项列表,列表荐这间以冒号分隔 |
SHLVL | shell的层级;每次启动一个新bash shell,该值增加1 |
TIMEFORMAT | 指定了shell的时间显示格式 |
TMOUT | select和read命令在没输入的情况下等待多久(以秒为单位),默认值 为0,表示无限长 |
TMPDIR | 目录名,保存bash shell创建 的临时文件 |
UID | 当前用户的真实用记ID(数字形式) |
设置PATH环境变量
PATH环境变量定义了用于进行命令和程序查找的目录。如果命令或者程序的位置没有包括 在PATH变量中,那么如果使用的不是绝对路径 的话,shell是没法找到的。所以把新的搜索目录添加到现有的PATH环境变量中。
PATH中各个目录之间是用冒号分隔的。你只需要引用原来的PATH值,然后再给这个字符串添加新目录就行了。
定位系统环境变量
登录shell
当你登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件时读取命令:
- /etc/profile
- $HOME/.bash_profile
- $HOME/.bashrc
- $HOME/.bash_login
- $HOME/.profile
/etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行启动这个文件。
另外4个启动文件是针对 用户的,可根据个人需求定制。
/etc/profile
每个发行版的/etc/profile文件都有不同的设置和命令
$HOME目录下的启动文件
交互式shell进程
非交互式shell
环境变量持久化
最好不要修改/etc/profile文件,如果你升级了所用的发行版,这个文件也会跟着更新,你所定制的变量就没有了。
最好是在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变量设置放在这个文件中。
数组变量
数组是能够存储多个值的变量。这些值可以单独引用,也可以作为整个数组来引用。
要给某个环境变量设置多个值,可以把值 放在括号里,值 与值之间用空格分隔
mytest=(one two three foru five)
echo $mytest
one
echo ${myest[2]}
three
echo ${mytest[*]}
one two three four five
myest[2] =seven
echo ${mytest[*]}
one two seven four five
unset mytest[2]
echo ${mytest[*]}
one two four five
echo ${mytest[2]}
echo ${mytest[3]}
four
理解Linux文件权限
Linux的安全性
/etc/passwd文件
此文件包含如下信息:
- 登录用户名
- 用户密码(X)
- 用户账户的UID(数字形式)
- 用户账户的组ID(GID)(数字形式)
- 用户账户的文本描述(称为备注字段)
- 用户HOME目录的位置
- 用户的默认shell
/etc/shadow文件
此文件对Linux系统密码管理提供了更多的控制。只有root用户才能访问/etc/shadow文件
它包含如下信息:
- 与/etc/passwd文件中的登录名字段对应的登录名
- 加密后的密码
- 自上次修改密码后过去的天数密码(自1970年1月1日开始计算)
- 多少天后才能更改密码
- 多少天后必须更改密码
- 密码过期前提前多少天提醒用户更改密码
- 密码过期后多少天禁用用户账户
- 用户账户被禁用的日期(自1970年1月1日到当天的天数表示)
- 预留字段给将来使用
添加新用户
用来向系统添加新用户的主要工具是useradd。这个命令可一次性创建新用户账户及设置用户HOME目录结构。
useradd命令使用系统的默认值 以及命令行参数来设置用户账户。
系统默认值 被设置在/etc/default/useradd文件中。可以使用加入了-D选项的useradd命令查看所用Linux系统中的这些默认值 。
在创建新用户时,如果你不在命令行中指定具体的值 ,useradd命令就会使用-D选项所显示的那些默认值。
- 新用户会被添加 到GID为100的公共组
- 新用户的HOME目录将会位于/home/loginname
- 新用户账户密码在过期后不会被禁用
- 新用户账户未被设置过期日期
- 新用户账户将bash shell作为默认shell
- 系统会将/etc/skel目录下的内容复制到新用户的HOME目录下
- 系统为该 用户账户在mail目录下创建 一个用于接收邮件的文件
要想在创建用户时改变默认值或默认行为,可以使用命令行参数,常用的如下:
参数 | 描述 |
---|---|
-c comment | 给新用户添加备注 |
-d home_dir | 为主目录指定一个名字(如果不想用登录名作为主目录名的话) |
-e expire_date | 用YYYY-MM-dd格式指定一个账户过期的日期 |
-f inactive_days | 指定这个用户密码过期 后多少天这个账户被禁用;0表示密码一过期就立即禁用,1表示禁用这个功能 |
-g initial_group | 指定用户登录组的GID或组名 |
-G goup … | 指定用户除登录组之外所属的一个或多个附加组 |
-k | 必须和-m一起使用,将/etc/skel目录的内容复制到用户的HOME目录 |
-m | 创建用户的HOME目录 |
-M | 不创建用户的HOME目录(当默认设置里要求创建时才使用这个选项) |
-n | 创建一个与用户登录名同名的新组 |
-r | 创建系统账户 |
-p passwd | 为用户账户指定默认密码 |
-s shell | 指定默认的登录shell |
-u uid | 为账户指定唯一 的UID |
删除用户
userdel
默认userdel只会删除/etc/passwd文件中的用户信息,而不会删除系统中属于该 账户的任何文件。
-r: 会删除用户的HOME目录以及邮件目录。
修改用户
用户账户修改工具:
命令 | 描述 |
---|---|
usermod | 修改用户账户的字段,还可以指定主要组以及附加组的所属关系 |
passwd | 修改已有用户的密码 |
chpasswd | 从文件中读取登录名密码对,并更新密码 |
chage | 修改密码的过期日期 |
chfn | 修改用户账户的备注信息 |
chsh | 修改用户账户的默认登录shell |
usermod
它能用来修改/etc/passwd文件中的大部分字段,参数大部分跟useradd命令的参数一样(比如,-c修改备注字段,-e修改过期日期,-g修改默认登录组)。另外还有一些
- -l修改用户账户的登录名
- -L锁定账户,使用户无法登录
- -p修改账户的密码
- -U解除锁定,使用户能够登录
passwd和chpasswd
如果只用passwd命令,它会改你自己的密码,系统上的任何用户都能修改自己的密码,但只有root用户才有权限修改别人的密码。
-e选项能强制用户下次登录时修改密码。
如果需要为系统中大量用户修改密码,chpasswd命令可以事半功倍。chpasswd命令能从标准输入自动密码对(由冒号分割)列表,给密码加密,然后为用户账户设置。
chsh、chfn和chage
此三个工具专门用来修改特定的账户信息。
chsh用来修改默认的用户登录shell。使用时必须用shell的全路径名作为参数。
chsh -s /bin/zsh username
chfn命令提供了在/etc/passwd文件的备注字段中存储信息的标准方法。
chage命令用来帮助管理用户账户的有效期。你需要对每个值设置多个参数
参数 | 描述 |
---|---|
-d | 设置上次修改密码到现在的天数 |
-E | 设置密码过期的日期 |
-I | 设置密码过期到锁定账户的天数 |
-m | 设置悠 密码之间最少要多少天 |
-W | 设置密码过期前多久天开始出现提醒信息 |
chage命令的日期值 可以用下面两咱方式的任意一种:
- YYYY-MM-DD格式的日期
- 代表从1970年1月1日到该 日期天数的数值
使用Linux组
/etc/group文件
和UID一样,GID在分配 时也采用了特定的格式。系统账户用的组通常会分配低于500的GID值。而用户组的GID则会从500开始分配。
/etc/group文件有4个字段:
- 组名
- 组密码
- GID
- 属于该 组的用户列表
组密码允许非组内成功通过它临时成为该 组成员。
创建新组
groupadd命令可以在系统上创建新组
修改组
组需要修改的信息不多。groupmod命令可以修改已有组的GID(加-g选项)或组名(加-n选项)
理解文件权限
使用文件权限符
ls可以用来查看Linux系统上的文件,目录和设备的权限
输出的第一个字段就是描述文件和目录权限的编码。
- -代表文件
- d代表目录
- l代表链接
- c代表字符型设备
- b代表块设备
- n代表网络设备
之后有3组三字符的编码。每一组定义了3种访问权限:
- r代表对象是可读的
- w代表对象是可写的
- x代表对象是可执行的
若没有某种权限,在该权限位会出现单破折线。这三组权限分别对应3个安全级别
- 对象的属主的权限
- 对象的属组的权限
- 系统其它用户的权限
默认文件权限
umask命令用来设置所创建文件和目录的默认权限。
umask是一个掩码。它会屏幕掉不想授予该 安全级别的权限。
要把umask值从对象的全权限值 中减掉。对文件来说,全权限的值是777;而对目录来说,则是666。所以要看明白默认权限需要使用全权限减去umask的值 。
改变安全性设置
改变权限
chmod options mode file
chmod参数可以使用八进制模式或符号 模式进行安全性设置。
e.g.
chmod 760 newfile
另一种方式:符号模式
ugoa ±= rwxXstugo…
第一组字符定义了权限的作用对象:
- u代表用户
- g代表组
- o代表其它
- a代表所有
第二组:
- +代表增加权限
- -代表移除权限
- =将权限设置成后面的值
第三组代表做得到设置对象上的权限。除rwx之外的意思
- X:如果对象是目录或者它已有执行权限,赋予执行权限
- s: 运行时重新设置UID或GID
- t: 保留文件或目录
- u: 将权限设置为跟属主一样
- g: 将权限设置为跟属组一样
- o:将权限设置为跟其他用户一样
改变所属关系
chown
chown options owner [ .group] file
共享文件
Linux每户上共享文件的方法是创建组。
Linux为每个文件和目录存储了3个额外的信息位
- 设置用户ID(SUID): 当文件被用户使用时,程序会以文件属主的权限运行
- 设置组ID(SGID):对文件来说,程序会以文件属组的权限运行;对目录来说,目录中创建的新文件会以目录的默认属组作为默认属组
- 粘着位:进程结束后文件还驻留(粘着)在内存中
要创建一个共享目录,使目录里的新文件都能沿用目录的属组,只需要将该目录的SGID位置位打开
chmod g+s dirname
管理文件系统
探索Linux文件系统
基本的Linux文件系统
ext文件系统
Linux最初采用的是一种简单的文件系统,它模仿了Unix的文件系统的功能。
使用虚拟目录来操作硬件设备,在物理设备上按定长的块来存储数据。
ext文件系统采用名为索引节点的系统来丰放虚拟 目录中所存储文件的信息。索引 节点系统在每个物理设备中创建 一个单独的表来存储这些文件的信息。ext文件系统名称中的extended部分来自其跟踪的每个文件的额外数据,包括:
- 文件名
- 文件大小
- 文件的属主
- 文件的属组
- 文件的访问权限
- 指向丰有文件数据的每个硬盘块的指针
Linux通过唯一数据(称作索引节点号)来引用索引节点表中的每个索引节点,这个值是创建文件时由文件系统分配 的。文件系统通过索引节点为号而不是文件全名及路径 来标识 文件。
ext2文件系统
ext2的索引节点表为文件添加了创建时间值,修改时间值 和最后访问时间值 来帮助系统管理员追踪文件的访问情况。ext2文件系统还将允许最大文件大小增加到了2TB(在ext2后期的版本中增加到了32TB)
除了扩展索引节点表外,ext2文件系统还改变了文件在数据块中存储的方式。保存文件时,ext2文件系统通过按 组分配磁盘块来减轻碎片化。通过将数据块组组,文件系统在读取文件时不需要为数据块查找整个物理设备。
日志文件系统
日志文件系统为Linux系统增加了一层安全性。它不再使用之前先将数据写入存储设备再更新索引节点表的做法,而是先将文件的更改写入到临时文件(称作日志,journal)中。在数据成功写到存储设备和索引节点表之后,再删除对应的日志条目。
Linux中有3种广泛使用的日志方法:
方法 | 描述 |
---|---|
数据模式 | 索引节点和文件都会被写入日志;丢失数据风险低,但性能差 |
有序模式 | 只有索引节点数据会被写入日志,但只有数据成功写入后才删除;在性能和安全性之间取得了良好的折中 |
回写模式 | 只有索引节点数据会被写入日志,但不控制文件数据何时写入;丢失数据风险高,但仍比不用日志好。 |
ext3文件系统
默认情况下ext3采用了有充模式的日志功能。
ext4文件系统
ext3的基础上支持了数据加密,还支持区段的特性(区段在存储设备上按块分配空间,但在索引节点表中只保存块起始位置。)
ext4还引入了块预分配技术。
Reiser文件系统
JFS文件系统
XFS文件系统
写时复制文件系统
copy-on-write
ZFS文件系统
ZFS是一个稳定 的文件系统,与Resier4,Btrfs和ext4势均力敌。它最大的弱项就是没有使用GPL许可。自2013年发起的OpenZFS项目有可能改变这种书面。但是,在获得GPL许可之前,ZFS有可能终无法成为Linux默认的文件系统。
Btrf文件系统
也被称为B树文件系统。
特点:稳定性,易用性以及能够动态调整已挂载文件系统的大小。
操作文件系统
创建分区
fdisk工具来帮助管理安装在系统上的任何存储设备,但得具有Root权限。
fdisk主要命令
命令 | 描述 |
---|---|
a | 设置活动分区标志 |
b | 编辑BSD Unix系统用的磁盘标签 |
c | 设置DOS兼容标志 |
d | 删除分区 |
l | 显示可用的分区类型 |
m | 显示命令选项 |
n | 添加一个新分区 |
o | 创建DOS分区表 |
p | 显示当前分区表 |
q | 退出,不保存更改 |
s | 为Sun Unix系统创建 |
t | 修改分区的系统ID |
u | 改变使用的存储单位 |
v | 验证分区表 |
w | 将分区表写入磁盘 |
x | 高级功能 |
创建文件系统
在将数据存储到分区之前,你必须用某种文件系统对其进行格式化,这样Linux才能使用它。每种文件系统类型都有自己的命令行程序来格式化分区。
工具 | 用途 |
---|---|
mkefs | 创建一个ext文件系统 |
mke2fs | 创建一个ext2文件系统 |
mkfs.ext3 | 创建一个ext3文件系统 |
mkfs.ext4 | 创建一个ext4文件系统 |
mkreiserfs | 创建一个ReiserFS文件系统 |
jfs_mkfs | 创建一个JFS文件系统 |
mkfs.xfs | 创建一个XFS文件系统 |
mkfs.zfs | 创建一个ZFS文件系统 |
mkfs.btrfs | 创建一个Btrfs文件系统 |
文件系统的检查与修复
fsck options filesystem
fsck能检查和修复大部分类型的Linux文件系统。文件系统可以通过设备名,在虚拟目录中的挂载点以及分配给文件系统的唯一UUID值来引用。
fsck的命令行选项:
选项 | 描述 |
---|---|
-a | 如果检测到错误,自动复文件系统 |
-A | 检查/etc/fstab文件中列出的所有文件系统 |
-C | 给支持进度条功能的文件系统显示一个进度条 |
-N | 不进行检查,只显示哪些检查会执行 |
-r | 出现错误时提示 |
-R | 使用-A选项时路过根文件系统 |
-s | 检查多个文件系统时,依次进行检查 |
-t | 指定要检查的文件系统类型 |
-T | 启动时不显示头部信息 |
-V | 在检查时产生详细输出 |
-y | 检测到错误 时自动 修改文件系统 |
fsck只能在未挂载的文件系统上运行。对大多数文件系统来说,你只需要卸载文件系统来进行检查,检查完成 之后重新挂载就好了。但是因为根文件系统含有所有核心的Linux命令和日志文件,所以你无法在处理于运行状态的系统上卸载它。这时你可以使用Linux LiveCD。
逻辑卷管理
如果用标准分区在硬盘 上创建了文件系统,为已有文件系统添加额外的空间多少是一种痛苦的体验。你只能在同一个物理硬盘的可用空间范围内调整分区大小。如果 硬盘上没有地方了,你就必须弄一个更大的硬盘,然后手动将已有的文件系统移动到新的硬盘上。
这时候可以通过将另外一个硬盘 上的分区加入已有文件系统,动态地添加存储空间。Linux逻辑卷管理器(logical volumn manage LVM)软件下好可以用来做这个。
逻辑卷管理布局
逻辑卷管理的核心在于如何处理安装在系统上的硬盘 分区。在逻辑卷管理的世界里,硬盘 称作物理卷(physical volumn, PV)。每个物理卷都会映射到硬盘 上特定的物理分区。
多个物理卷集中在一起可以形成一个卷组(volume group, VG)。逻辑卷管理系统将卷组视为一个物理硬盘,但事实 上卷组可能是由分布在多个物理硬盘 上的多个物理分区组成的。卷组提供了一个创建逻辑分区的平台,而这些逻辑分区则包含了文件系统
整个结构中的最后一层是逻辑卷(logical volume,LV)逻辑卷为Linux提供了创建文件系统的分区环境,作用类似于到目前为止我们一直在探讨 的Linux中的物理硬盘分区。Linux系统将逻辑卷视为物理分区。
Linux中的LVM
Linux LVM有两个可用的版本: LVM1, LVM2
快照
最初的Linux LVM允许你在逻辑卷在线的状态 下将其复制到另一个设备。
条带化
LVM2提供,条带化,可跨多个物理硬盘创建逻辑卷。当LinuxLVM将文件写入逻辑卷时,文件中的数据块会被分散到多个硬盘上。每个后继数据块会被写到下一个硬盘上。
条带化有助于提高硬盘性能。因为Linux可以将一个文件的多个数据块同时写入多个硬盘而无需等待单个硬盘移动读写磁头到多个不同位置。
镜像
LVM镜像是一个实时更新的逻辑卷的完整副本。
使用Linux LVM
-
定义物理卷
创建过程的第一步就是将硬盘上的物理分区转换成Linux LVM使用的物理卷区段。在创建了基本的Linux分区后,你需要通过t命令改变分区的类型。
fdisk /dev/sdX
t
8e
p
w
q
下一步是用分区来创建实际的物理卷。可以通过pvcreate命令
sudo pvcreate /dev/sda1
如果你想查看创建进度的话,你可以使用pvdisplay命令来显示已创建的物理卷列表
sudo pvdisplay /dev/sda1
-
创建卷组
vgcreate命令
sudo vgcreate Vol1 /dev/sdb1
vgdisplay Vol1
-
创建逻辑卷
Linux系统使用逻辑卷来模拟物理分区,并在其中保存文件系统。Linux系统会像处理物理分区一个处理逻辑卷,允许你定义逻辑卷中的文件系统,然后将文件系统挂载到虚拟目录上。
要创建逻辑卷,使用lvcreate命令,lvcreate命令的选项如下:
选项 | 长选项名 | 描述 |
---|---|---|
-c | –chunksize | 指定快照逻辑卷的单位大小 |
-C | –contiguous | 设置或重置连续分配策略 |
-i | –stripes | 指定条带数 |
-I | –stripesize | 指定每个条带的大小 |
-l | –extents | 指定分配给新逻辑卷的逻辑区段数,或者要用的逻辑区段的百分比 |
-L | –size | 指定分配给新逻辑卷的硬盘大小 |
–mirror | 指定的次设备号 | |
-m | –mirrors | 创建逻辑卷镜像 |
-M | –persistent | 让次设备号一直有效 |
-n | –name | 指定新逻辑卷的名称 |
-p | –permission | 为逻辑卷设置读/写权限 |
-r | –readahead | 设置预读扇区数 |
-R | –regionsize | 指定将镜像分成多大的区 |
-s | snapshot | 创建快照逻辑卷 |
-Z | –zero | 将新逻辑卷的前1KB数据设置为零 |
e.g.
sudo lvcreate -l 100%FREE -n lvtest Vol1
-
创建文件系统
sudo mkfs.ext4 /dev/Vol1/lvtest
-
修改LVM
Linux LVM常用命令
命令 功能 vgchange 激活和禁用卷组 vgremove 删除卷组 vgextend 将物理卷加到卷组中 vgreduce 从卷组中删除物理卷 lvextend 增加逻辑卷的大小 lvreduce 减小逻辑卷的大小
安装软件程序
包管理基础
PMS(package Management System, PMS)会利用一个数据库来记录各种相关内容:
- Linux系统上已安装了什么软件包
- 每个包安装了什么文件
- 每个已安装软件包的版本
基于debian的系统
dpkg命令是Debian每户PMS的工具的核心。包含在这个PMS中的其他工具有:
- apt-get
- apt-cache
- aptitude
使用apt管理软件包
基于Red Hat的系统
yum
从源码安装
使用编辑器
vim编辑器
nano编辑器
emacs编辑器
KDE系统编辑器
KWrite编辑器
Kate编辑器
GNOME编辑器
gedit
Shell脚本编程基础
构建基本脚本
使用多个命令
shell脚本的关键在于输入多个命令并处理每个命令的结果,甚至需要将一个命令的传给另一个命令。shell可以让你将多个命令串起来,一次执行完成。如果两个命令一起运行,可以把它们放在同一行中,彼此间用分号隔开。
创建shell脚本
在创建shell脚本文件时, 必须在文件的第一行指定要使用的shell,格式为:
#!/bin/bash
shell除第一行外不会解释#开头的行
显示消息
大多数shell命令都会产生自己的输出。这些输出会显示在脚本所运行的控制台显示器上。你可能想要添加自己的文本消息来告诉用户脚本 正在做什么。可以通过echo命令来实现这一点
echo this is a message
默认情况下,不需要使用引号将要显示的文本字符串划定出来。但有时在字符串中出现引号的话就比较麻烦了。你需要使用另一种引号把字符串划定起来。
如果想把文本字符和命令输出显示在同一行中,可以使用echo语句的-n参数。
使用变量
环境变量
在脚本中,你可以在环境变量前加上($)来使用这些系统环境变量。
但你如果想显示 , 那 么 则 需 要 在 ,那么则需要在 ,那么则需要在前加一个\
用户变量
除了环境变量,shell脚本还允许在脚本中定义和使用自己的变量。
用户变量可以是任何由字母,数字,下划线组成的文本字符串,长度不超过20个。
使用等号将值赋给用户变量。在变量,等号和值之间不能出现空格。
shel脚本会自动决定变量值的数据类型。在脚本 的整个生命周期里,shell脚本中定义的变量会一直保持着它们的值,但在shell脚本结束时会被删除掉。
与系统变量类似,用户变量可通过美元符号引用。
命令替换
shell脚本中最有用的特性之一就是可以从命令输出中提取信息,并将其赋值给变量。把输出赋给变量后,就可以随意在脚本中使用了。这个特性在处理脚本数据时尤为方便。
有两种方法可以将命令输出赋值给变量:
- 反引号字符(`)
- $()格式
e.g.
testing=
date
testing-$(date)
重定向输入和输出
输出重定向
最基本的重定向将命令的输出发送到一个文件中。bash shell 用大于号(>)来完成这项功能。
command > outputfile
输入重定向
输入重定向将谇折内容重定向到命令,而非将命令的输出重定向到文件。使用(<)符号:
command < inputfile
e.g.
$ wc < testfile
2 11 60
wc命令可以对数据文本进行计数。默认它会给出3个值:
- 文本的行数
- 文本的词数
- 文本的字节数
内联输入重定向
这种方法无需使用文件进行重定向,只需要在命令行中指定用于输入 重定向的数据就可以了。
内联输入重定向符号是远于小号(<<)。除了这个符号,你必须指定一个文本标记来划分输入数据的开始和结尾。任何字符串都可以作为文本标记,但在数据的开始和结尾文本必须一致。
e.g.
$ wc << EOF
> test one
> test two
> test three
> EOF
管道
有时需要将一个命令的输出作为另一个命令的输入。可以使用重定向来实现,只是有些笨拙。可以使用管道操作符(|)
command1 | command2
管道操作符两边的命令会同时运行。在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲。
执行数学运算
在shell中执行数据运算比较麻烦,可以使用两种途径来进行
expr命令
e.g.
$ expr 1 + 5
6
expr命令的操作符
操作符 | 描述 |
---|---|
ARG1 | ARG2 | 如果ARG1妈不是null也不是零值,返回ARG1,否则返回ARG2 |
ARG1 & ARG2 | 如果没有参数是null或零值,返回ARG1, 否则返回0 |
ARG1 < ARG2 | 如果ARG1小于ARG2,返回1,否则 返回0 |
ARG1 <= ARG2 | 如果 ARG1小于或等于ARG2返回1,否则返回0 |
ARG1 = ARG2 | 如果ARG1等于ARG2 返回1,否则返回0 |
ARG1 != ARG2 | 如果ARG1不等于ARG2返回1,否则返回0 |
ARG1 >= ARG2 | 如果ARG1大于等于ARG2返回1,否则返回0 |
ARG1 > ARG2 | 如果ARG1大于ARG2返回1,否则返回0 |
ARG1 + ARG2 | 返回ARG1和ARG2的合 |
ARG1 - ARG2 | 返回ARG1各ARG2的算术运算差 |
ARG1 * ARG2 | 返回ARG1和ARG2的算术乘积 |
ARG1 /ARG2 | 返回ARG1和ARG2的算术商 |
ARG1 % ARG2 | 返回ARG1被ARG2除的算术余数 |
ARG1 : ARG2 | 如果REGEXP匹配到了STRING中的某个模式,返回该 模式匹配 |
match STRING REGEXP | 如果REGEXP匹配到了STRING中的某个模式,返回该模式匹配 |
substr STRING POS LENGTH | 返回起始位置为POS(从1开始计数),长度为THLENGH个字符的子字符串 |
index STRING CHARS | 返回在STRING中找到CHARS字符串的位置;否则返回0 |
length STRING | 返回字符串STRING的数值长度 |
+ TOKEN | 将TOKEN解释成字符串,即使是个关键字 |
(EXPRESSION) | 返回EXPRESSION的值 |
尽管标准操作符在expr命令中工作得很好,但在脚本 或命令行上使用它们时仍有问题出现。许多expr命令的操作符在shell中另有含义(比如星号)。当它们出现在expr命令中时,会得到一些诡异的结果。
要解决这样的问题,需要对那些容易被shell错误解释的字符,在它们传入expr命令之前进行转义。
但是在shell中使用expr命令也同样复杂。
使用方括号
在bash中,在将一个数学运算结果赋给某个变量时,可以用美元符和方括号($[ operation ])将数学表达式围起来。
浮点解决方案
有几种解决方案能够克服bash中数学运算的整数限制。最常见的方案是用内建的bash计算器, 叫做bc.
bc的基本用法
bash计算器能够识别:
- 数字(整数和浮点数)
- 变量(简单变量和数组)
- 注释(以#或c语言中的/* */开始的行)
- 表达式
- 编程语句(例如 if -then语句)
- 函数
在脚本中使用bc
variable=$(echo “options; expression” | bc)
e.g.
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
退出脚本
shell中运行的每个命令都使用退出状态码(exit status)告诉shell它已经运行完毕。退出状态码是一个0~255的整数值,在命令结束运行时由命令传给shell。可以捕获这个值 并在脚本中使用
查看退出状态码
Linux提供了一个专门的变量$?来保存上个已执行命令的退出状态码。
按照惯例,一个成功结束的命令的退出状态码是0.如果一个命令结束时有错误,退出状态码就是一个正数值。有一些参考:
状态码 | 描述 |
---|---|
0 | 命令成功结束 |
1 | 一般性未知错误 |
2 | 不适合的shell命令 |
126 | 命令不可执行 |
127 | 没找到命令 |
128 | 无效的退出参数 |
128+x | 与Linux信号x相关的严重错误 |
130 | 通过Ctrl + C终止的命令 |
255 | 正常范围之个的退出状态码 |
exit命令
默认情况下,shell脚本会以脚本中最后一个命令的退出状态码退出。
你可以改变这种默认行为,返回自己的退出状态码。exit命令允许你在脚本结束时指定一个退出状态码
e.g.
$ exit 5
使用结构化命令
使用if-then语句
if command
then
commands
fi
if后面的那个命令执行成功,位于then部分的命令就会被执行。如果该命令的退出状态码是苊值。then部分的命令就不会被执行。
if-then-else语句
if command
then
commands
else
commands
fi
嵌套if
if command1
then
commands
elif command2
then
more commands
fi
test命令
test condition
数值比较
test命令的数值比较功能
比较 | 描述 |
---|---|
n1 -eq n2 | 检查n1是否与n2相等 |
n1 -ge n2 | 检查n1是否大于或等于n2 |
n1 -gt n2 | 检查n1是否大于n2 |
n1 -le n2 | 检查n1是否小于或等于n2 |
n1 -lt n2 | 检查n1是否小于n2 |
n1 -ne n2 | 检查n1是否不等于n2 |
e.g.
value = 6
if [ $value -gt 5 ]
then
echo "The test value $value is greater than five"
fi
字符串比较
条件测试还允许比较字符串值。比较字符串比较烦琐,常用测试:
比较 | 描述 |
---|---|
str1 = str2 | 检查str1是否和str2相同 |
str1 != str2 | 检查str1是否和str2不同 |
str1 < str2 | 检查str1是否比str2小 |
str1 > str2 | 检查str1是否比str2大 |
-n str1 | 检查str1的长度是否非0 |
-z str1 | 检查str1的长度是否为0 |
字符串相等性
在比较字符串的相等性时,比较测试会将所有的标点和大小写情况都考虑在内。
字符串顺序
问题:
- 大于号和小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件名;
- 大于和小于顺序和sort命令所采用的不同:在比较测试中,大写字母被认为是小于小写字母的。但sort命令却恰好相反。原因是比较测试中使用的是标准的ASCII顺序,根据每个字符的ASCII数值来决定排序结果,sort命令使用的是系统本地化语言设置中定义的排序顺序。
字符串大小
-n 和 -z可以检查一个变量是否含有数据
文件比较
test命令的文件比较功能:
比较 | 描述 |
---|---|
-d file | 检查目标是否存在并是一个目录 |
-e file | 检查目标是否存在 |
-f file | 检查是否存在并是一个文件 |
-r file | 检查目标是否存在并可读 |
-s file | 检查目标是否存在并非空 |
-w file | 检查目标是否存在并可写 |
-x file | 检查目标是否存在并可执行 |
-O file | 检查目标是否存在 并属于当前用户 |
-G file | 检查目标是否存在并默认组与当前用户相同 |
file1 -nt file2 | 检查file1是否比file2更新 |
file1 -ot file2 | 检查file1是否比file2旧 |
复合条件测试
if-then语句允许你使用布尔值逻辑来组合测试。有两种布尔值值运算符可用:
-
[ condition1 ] && [ condition2 ]
两种条件必须完全满足
-
[ condition1 ] || [ condition2 ]
两种条件只需满足一种
if-then的高级特性
- 用于数学表达式的双括号
- 用于高级字符串处理功能的双方括号
使用双括号
双括号命令允许你在比较过程中使用高级数学表达式。test命令只能大比较中使用简单的算术操作。双括号命令提供了更多 多的数学符号,这些符号对于用过其他编程语言的程序员而言并不陌生,格式如下:
(( expression ))
双括号命令符号:
符号 | 描述 |
---|---|
val++ | 后增 |
val– | 后减 |
++val | 先增 |
–val | 先减 |
! | 逻辑求反 |
~ | 位求反 |
** | 幂运算 |
<< | 左位移 |
>> | 右位移 |
& | 位布尔和 |
| | 位布尔或 |
&& | 逻辑和 |
|| | 逻辑或 |
使用双方括号
双方括号提供了针对字符串比较的高级特性,格式如下:
[[ expression ]]
双方括号里的expression使用了test命令中采用的标准字符串比较。但它提供了test命令未提供的另一个特性——模式匹配(pattern matching).
在模式匹配中,可以定义一个正则表达式来匹配字符串的值
e.g.
#!/bin/bash
if [[ $USER == R* ]]
then
echo "Hello $USER"
else
echo "Sorry, I don't know you"
fi
case命令
有了case命令,就不需要再写出所有的elif语句来不停地检查同一个变量的值了。格式如下:
case variable in
pattern1 | pattern2) commands1;;
parrtern3) commands2;;
*) default commands;;
esac
更多结构化命令
for命令
for命令允许你创建一个遍历一系统值 的循环。
基本格式:
for var in list
do
commands
done
读取列表中的值
e.g.
for test in Alabama Alaska Arizona Arkansas
do
echo "The next state is $test"
done
读取列表中的复杂值
e.g.
for test in I don't know if this'll work
do
echo "word:$test"
done
---
word:I
word:dont know if thisll
word:work
shell看到了列表值中的单引号并尝试使用它们来定义一个单独的数据值。
有两种办法解决这个问题:
- 使用转义字符来将单引号转义
- 使用双引号来定义用到单引号的值
从变量读取列表
从命令读取值
e.g.
#!/bin/bash
file = "states"
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
更改字段分隔符
造成这个问题的原因是特殊的环境变量IFS, 叫作内部字段分隔符(internal field separator).IFS环境变量定义了bash shell用作字符分隔符的一系列字符。默认情况下,bash shell会将下列字符当作字段分隔符。
- 空格
- 制表符
- 换行符
如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明列表 中一个新数据字段的开始。在处理可能含有空格的数据(比如文件名)时,这空运 非常麻烦。
要解决这个问题,可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段分隔符的字符。
IFS=$"\n"
将这个语句加入到脚本中,告诉bash shell在数据值中忽略空格和制表符。
用通配符读取目录
最后,可以用for命令来自动遍历目录中的文件。进行操作时,必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展配置。文件扩展匹配是生成匹配指定通配符的文件名或路径名的过程。
e.g.
#!/bin/bash
# iterate through all the files in a directory
for file in /home/*
do
fi [ -d "$file"]
then
echo "$file is a directory"
elif [ -f "$file"]
then
echo "$file is a file"
fi
done
C语言风格的for命令
for (( variable assignment ; condition ; iteration process))
e.g.
for (( a = 1; a < 10; a++))
注意:
- 变量赋值可以有空格;
- 条件中的变量不以美元符开头
- 迭代过程的算式未用expr命令格式
使用多个变量
C语言风格的for命令也允许为迭代使用多个变量。循环会单独处理每个变量,你可以为每个变量定义不同的迭代过程。尽管可以使用多个变量,但你只能在for循环中定义一种条件。
for (( a = 1, b = 10; a <-10; a++, b--))
while命令
while命令某种单方上是if-then语句和for循环的混杂体。格式如下:
while test command
do
other commands
done
while命令定义了每次迭代时检查的测试条件成立性。
使用多个测试命令
while命令允许你在while语句行定义多个测试命令。只有最后一个测试命令的退出状态 码会被用来决定什么时候结束循环。
util命令
util命令和while命令工作的方式完全相反。util命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。一量测试命令返回了退出状态码0,循环就结束了。
until test commands
do
other commands
done
和while类似,你可以在util命令语句中放入多个测试命令。只有最后一个命令的退出状态码决定了bash shell是否执行已定义的other comands。
嵌套循环
循环语句可以在循环内使用任意类型的命令,包括其他循环命令。这种循环叫做嵌套循环。
循环处理文件数据
通常必须遍历存储在文件中的数据。这要求结合已经进过的两种技术:
- 使用嵌套循环
- 修改IFS环境变量
典型的例子就是处理/etc/passwd文件中的数据。这要求你逐行遍历/etc/passwd文件。并将IFS变量的值改成冒号,这样就能分隔开每行中的各个字段值了。
#!/bin/bash
# change this IFS Value
IFS.OLD = $IFS
IFS=$'\n'
for entry in $(cat /etc/passwd)
do
echo "Values in $entry -"
IFS=:
for value in $entry
do
echo " $value"
done
done
控制循环
如果不能控制循环,那么一旦启动了循环,就必须等待循环完成所有迭代才会停止。
有两个命令能帮助我们控制循环内部的情况:
- break
- continue
break命令
break命令是退出循环的一个简单方法。可以使用break命令来退出任意类型的循环。
-
单层循环
-
内部循环
-
外部循环
语法:
break n #其中n指定了要跳出的循环层级。默认情况下n为1,表明跳出的是当前的循环。如果你将n设为2,break命令会停止下一级的外部循环。
continue
continue命令可以提前中止某次循环中的命令,但并不会完全终止整个循环。
处理循环的输出
在shell脚本中你可以对循环的输出使用管道或进行重定向。这可以通过在done命令之后添加一个处理命令来实现
for file in /home/rich/*
do
if [ -d "$file"]
then
echo "$file is a directory"
elif
echo "$file is a file"
fi
done > output.txt
处理用户输入
命令行参数
向shell脚本传递数据的最基本方法是使用命令行参数。命令行参数允许在运行脚本时向命令行添加数据。
e.g.
$ ./addem 10 30
读取参数
bash shell会将一些称为位置参数的特殊变量分配 给输入到命令行中的所有参数。这也包括shell所执行的脚本名称。公交车参数变量是标准的数字:
-
$0: 程序名
-
$1: 第一个参数
-
$2: 第二个参数
…
直到第九个参数$9
如果脚本需要的命令行参数不止9个,你仍然可以处理,但是需要稍微修改一下变量名。在第9个变量之后,你必须在变量数字周围加上花括号,比如${10}。
读取脚本名
使用$0参数获取shell在命令行启动的脚本名。
当传给$0变量的实际字符串不仅仅是脚本名,而是完整的脚本路径时,变量$0变会使用整个路径。
e.g.
$ bash /home/Christine/test.sh
The zero paramter is set to : /home/Christine/test.sh
测试参数
当脚本认为参数变量中会有数据而实际上并没有时,脚本很有可能会产生错误消息。这种写脚本的方法并不可取。在使用参数前一定要检查其中是否存在数据。
e.g.
#!/bin/bash
if [ -n "$1" ]
then
echo Hello $1.
else
echo "Sorry, you did not identify yourself"
fi
我们可以使用-n测试来检测命令行参数$1中是否有数据。
特殊参数变量
参数统计
特殊变量$#含有脚本运行时携带的命令行参数的个数。可以在脚本中任何地方使用这个特殊变量。
抓取所有的数据
∗ 和 *和 ∗和@变量可以用来轻松访问所有参数。
KaTeX parse error: Expected 'EOF', got '\*' at position 1: \̲*̲变量会将命令行上提供的所有参数…*变量会将这些参数视为一个整体,而不是多个个体。
而$@变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词。这样就能够遍历所有的参数值,得到每个参数了。
移动变量
bash shell工具箱中另一件工具是shift命令。它能够用来操作命令行参数。shift命令会根据它们的相对位置来移动命令行参数。
在默认情况下,它会将每个参数变量向左移动一个位置。所以变量$3的值会移到$2, 变量$2的值会移到$1, 而变量$1的值则会被删除。而$0的值则不会变。
处理选项
查找选项
命令行选项(是跟在单破折线后面的单个字母,它能改变命令的行为),可以像处理命令行参数一样处理命令行选项。
-
处理简单选项
你可以使用处理脚本 程序携带的命令行参数一样处理命令行选项。
如在提取每个单独参数时,使用case语句来判断某个参数是否为选项。
-
分离参数和选项
shell中会有同时使用选项和参数的情况。Linux中处理这个问题的标准方式是用特殊字符来将二者分开。如–
-
处理带值的选项
使用getopt命令
getopt命令是一个在处理命令行选项和参数时非常方便的工具。它能够识别命令行参数。
-
命令的格式
getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当 的格式。命令格式如下:
getopt optstring parameters
-
在脚本中使用getopt
set – ( g e t o p t − q a b : c d " (getopt -q ab:cd " (getopt−qab:cd"@")
getopt命令并不擅长处理带空格和引号的参数值。它会将空格当用参数分隔符,而不是根据双引号将二者当作一个参数。
使用更高级的getopts
getopts内建于bash shell。 它跟近亲getopt看起来很像,但多了一些扩展功能。
与getopt不同,前者将命令行上选项和参数处理后只生成一个输出,而getopts命令能够和已有的shell参数变量配合默契。
每次调用 它时,它一次只处理命令行上检测到的一个参数。处理完所有的参数后,它会退出并个大于0的退出状态码。这让它非常适合解析命令行所有的参数的循环中。
getopts后面的字符串就是可以使用的选项列表,每个字母代表一个选项,后面带:意味着选项除了定义本身之外,还会带上一个参数作为选项的值,getopts字符串中没有跟随:的是开关型选项,不需要再指定值,相当于true/false,只要事字这个参数就是true。如果命令行中包含了没有在getopts列表中的选项,会有警告信息,如果在整个getopts字符串加上一个:,就能消除警告信息了。
格式如下:
gettopts [optstring[:]][descrition] variable
- optstring: 表示为某个脚本可以使用的选项
- “:”: 如果某个选项(optstring)后面出现了冒号,则表示这个选项后面可以接参数(即一段描述信息description)
- variable: 表示将某个选项保存在变量variable中
getopts会用到两个环境变量。如果需要跟一个参数值,OPTARG环境变量就会保存这个值。OPTIND环境变量保存了参数列表中getopts正在处理的参数位置。这样你就能在处理完选项这后继续处理其他命令行参数了。 - OPTARG: 就是将选项后面的参数或者描述信息保存在这个变量中
- OPTIND:这个表示命令行的下一个选项或参数的索引(文件名不算选项或参数)。
e.g.
#!/bin/bash
echo $*
while getopts ":a:bc:" opt
do
case $opt in
a)
echo $OPTARG $OPTIND;;
b)
echo "b $OPTIND";;
c)
echo "c $OPTIND";;
?)
echo "error"
exiit 1;;
esac
done
echo $OPTIND
shift $(( $OPTIND -))
echo $0
echo $*
执行结果如下:
sh getopts.sh -a 11 -b -c 6
-a 11 -b -c 6
11 3
b 4
c 6
6
getopts.sh
解释:
- while getopts “?️bc:" opt # 第一个冒号表示忽略错误;字符后面的冒号表示该 选项必须有自己的参数。
- $OPTARG 存储相应选项的参数,如上例中的11, 6
- OPTIND总是存储原始$*中下一个要处理的选项(不是参数,而是选项,此处指的是a,b,c这三个选项,而不是那些数字,当然数字也是会占有位置的)的位置。
getopts与getopt的区别
- getopts是shell内建的命令,getopt是一个独立外部工具
- getopts的使用语法简单,而getopt使用语法较为复杂
- getopts不支持长参数,getopt支持
- getopts不会重排所有参数的顺序,而getopt会
- getopts出现的目的是为了代替getopt较快捷的执行参数分析工作
将选项标准化
在创建shell脚本时,你完全可以决定用哪些字母选项以及它们的用法。但有些字母选项在Linux世界里已经拥有了某种程度的标准含义。如果你能在shell脚本中支持这些选项,脚本看起来能更友好一些。
下面显示了Linux中用到的一些命令行选项有常用含义:
选项 | 描述 |
---|---|
-a | 显示所有对象 |
-c | 生成一个计数 |
-d | 指定一个目录 |
-e | 扩展一个对象 |
-f | 指定读入数据的文件 |
-h | 显示命令的帮助信息 |
-i | 忽略文本大小写 |
-l | 产生输出的长格式版本 |
-n | 使用非交互模式 |
-o | 将所有输出重定向到指定的输出文件 |
-q | 以安静模式运行 |
-r | 递归地处理目录和文件 |
-s | 以安静模式运行 |
-v | 生成详细输出 |
-x | 排除某个对象 |
-y | 对所有问题回答yes |
获得用户输入
比如你想要在脚本 运行时问个问题,等待运行脚本 的人来回答。bash shell为此提供了read命令。
基本的读取
read命令从标准输入(通常是键盘)或另一个文件描述符中接受输入。在收到输入后,read命令会将数据放进一个变量。
e.g.
#!/bin/bash
#testing the read commannd
echo -n "Enter you name: "
read name
echo "Hello $name, welcome to my program."
./test.shh
Enter you name: Rich
hello Rich, welcome to my proogram.
注意,生成提示的echo命令使用了-n选项,该 选项不会在字符串末尾输出换行符。
实际上read命令包含了-p选项,允许你直接在read命令行指定提示符。
read -p "Please enter you age: " age
超时
使用read命令时要当心,脚本很可能会一直等待用户输入。如果不管是否有数据输入,脚本都必须执行,你可以使用-t选项指定一个计时器。-t选项指定了read命令的等待输入的秒数。当计时器过期后,read命令会返回一个非零的退出状态码。
隐藏方式读取
有时你需要脚本从用户处得到输入,但又不在屏幕上显示输入信息,比如输入密码。你可以使用-s选项。(其实-s选项只是将文本颜色设置成 跟背景色一样)
从文件中读取
最后,也可以用read命令来读取Linux系统上文件里保存的数据。每次调用read都会从文件中读取一行文本。当文件中没有内容时,read命令会退出并返回非零状态码。
其中最难的部分是将文件中的数据传给read命令,最常用的方法是对文件使用cat,将结果通过管理直接传给含有read命令的while命令。
e.g.
#!/bin/bash
reading data from a file
count=1
cat test | while read line
do
echo "Line number: $line"
count=$[ $count + 1]
done
echo "Finished processing thhe file"
while循环会持续通过read命令处理文件中的行,直到read命令以非零退出状态码退出。
呈现数据
理解输入和输出
标准文件描述符
Linux将每个对象当作文件来处理。这包括输入和输出进程。Linux用文件描述符来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开的文件。每个进程一次最多可以有九个文件描述符。出于特殊目的,bash shell保留了前三个谁的描述符(0, 1, 2)
Linux的标准文件描述符:
文件描述符 | 缩写 | 描述 |
---|---|---|
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准错误 |
- STDIN
STDIN文件描述符代表shell的标准输入。对终端来说,标准输入就是键盘。
在使用输入重定向符号(<)时,Linux会重定向指定的文件来替换标准输入文件描述符。它会读取文件并提取数据,就如同它是键盘上的键入一样。 - STDOUT
STDOUT文件描述符代表shell的标准输出。在终端界面上,标准输出就是终端显示器。shell的所有输出(包括shell中运行的程序脚本)会被定向到标准输出,也就是显示器。
你也可以使用输出重定向来改变(>) - STDERR
shell通过特殊的STDERR文件描述符来处理错误消息。STDERR文件描述符代表shell的标准错误输出。默认,错误消息也会输出到显示器输出中。但STDERR并不会随着STDOUT的重定向而发生改变。
重定向错误
- 只重写向错误
ls -all badfile 2> errorMsg
使用2>可以将错误重定向到指定文件或其它位置,这样,错误消息就不会出现在屏幕上了。
- 重定向错误和数据
如果想重定向错误和正常输出,必须用两个重定向符号。需要在符号前面放上待重定向数据所对应的文件描述符,然后指向用于保存数据的输出文件。
ls -all testt test2 badfiile 2> faiiMsg 1> msg
- w全部重定向
ls -lah fiile badfile &> alllMsg
在脚本中重定向输出
有两种方法在脚本中重定向输出:
- 临时重定向行输出
- 永久重定向脚本中的所有命令
临时重定向
如果有意思在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR。你所需要做的是使用输出重定向符来将输出信息重定向到STDERR文件描述符。在重定向到文件描述符时,你必须在文件描述符数字之前加一个&
echo "This is an error messagge " >&2
如果像平时一样运行这个脚本,不会发生任何改变,因为默认情况下,Linux会将STDERR导向STDOUT。但是,如果你在运行脚本时重定向了STDERR,脚本中所有导向STDERR的文本都会被重定向。
永久重定向
可以使用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。
exec 1> msg
exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给STDOUT的所有输出都会被重定向到文件msg
在脚本中重定向输入
exec命令允许你将STDIN重定向到Linux系统的文件中:
exec 0< testfile
这个命令会告诉shell它应该从文件testfile中获得输入,而不是STDIN。这个重定向只要在脚本需要输入时就会作用。
创建自己的重定向
创建输出文件描述符
可以使用exec命令来给输出分配文件描述符。和标准的文件描述符一样,一旦将另一个文件描述分配给一个文件,这个重定向就会有一直有效,直到你重新分配。
e.g.
#!/bin/bashh
#usiing an alternative fiile descriptor
exec 3> test3out
echo "This should diispplay on the monitor"
echo "and thhis shhould be shtoored in the file" >&3
echo "Then thhiis should be bac on thhe montoor"
$ ./test
This shhould display on thhe montor
Thhis thhiis shhould be back on thhe montoor
cat test3out
and this should be stored in the file
这个脚本用exec命令将文件描述符3重定向到另一个文件。
重定向文件描述符
你可以分配另外一个文件描述符给标准文件描述符,反之亦然。这意味着你可以将STDOUT的原来位置重定向到另一个文件描述符,然后再利用该文件描述符重定向回STDOUT。
e.g.
#!/bin/bash
#sttoring STDOUT, thhen cooming back to it
exec 3>&1
exec 1>test4out
echo "This should store in the output file"
eccho "allong with thhe line"
exec 1>&3
echo "Now thiings should be back to normall"
.test
Now thhings should be back too normal
cat test4out
This should store in thhe output fiile
along with thhiie line
创建输入文件描述符
可以用和重定向输出文件描述符同样的办法重定向输入文件描述符。在重定向到文件之前,先将STDIN文件描述符保存到另外一个文件描述符,然后在读取完文件之后再将STDIN恢复到它原来的位置。
e.g.
#!/bin/bash
#redirecting input file descriiptors
exec 6<&0
exec 0<testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1]
done
exec 0<&6
read -p "Are you done now?" answer
case $annswer in
Y|y) echo "Goodbye";;
N|n) echo "Sorry, thhis is the end.";;
esac```
创建读写文件描述符
exec 3<> testfile
关闭文件描述符
shell会在脚本退出时自动关闭你创建的新输入或输出文件描述符。然而在有些情况下,你需要在脚本结束前手动关闭文件描述符。需要将它重定向特殊符号&-.
exec 3>&-
列出打开的文件描述符
lsof命令会列出整个Linux系统打开的所有文件描述符。
常用参数
- -p :允许指定PID
- -d: 允许指定要显示的文件描述符编号
要想知道进程当前的PID,可以用特殊变量$$(shell会将它设为当前PID)。-a选项来对其他两个选项的结果执行布尔And运算,e.g.
/usr/sbin/lsof -a -p $$ -d 0,1,2
lsof默认有7列信息,如下:
列 | 描述 |
---|---|
COMMAND | 正在运行的命令名的前9个字符 |
PID | 进程的PID |
USER | 进程属主的登录名 |
FD | 文件描述符号以及访问类型(r代表读,w代表写,u代表读写) |
TYPE | 文件的类型(CHR代表字符型, BLK代表块型,DIR代表目录,REG代表常规文件 |
DEVICE | 设备的设备号(主设备和从设备号) |
SIZE | 如果有的话,表示文件的大小 |
NODE | 本地文件的节点号 |
NAME | 文件名 |
与STDIN, STDOUT,TDERR关联的文件类型是字符型。因为STDIN, STDOUT和STDERR文件描述符都指向终端,所以输出的名称就是终端的设备名。
阻止命令输出
如果运行在后台的脚本出现错误消息,shell会通过电子邮件将它们发给进程的属主。这会很麻烦,尤其是当运行会生成很多烦琐的小错误的脚本时。要解决这个问题,可以将STDERR重定向到一个叫作null文件的特殊文件。相当于全部被丢掉了。
ls -la > /dev/null
创建临时文件
Linux系统有特殊的目录,专供临时文件使用。Linux使用/tmp目录来存放不需要永久保留的文件。大多数Linux发行版配置了系统在启动时自动删除/tmp目录的所有文件。
创建本地临时文件
默认情况下,mktemp会在本地目录中创建一个文件。要用mktemp命令在本地目录中创建一个临时文件,你只要指定一个文件名模板就行了。模板可以包含任意文本文件,在文件名末尾加上6个X就可以了。
mktemp命令会用6个字符码替换这6个X,从而保证文件在目录中的唯一性。
mktemp命令的输出正是它所创建的文件的名字。在脚本中使用mktemp命令时,可能要将文件名保存到变量中,这样就能在后面的脚本中引用了。
tempfilename = $(mktemp testfile.XXXXXX)
在/tmp目录创建临时文件
-t选项会强制mktemp命令在临时目录来创建该文件。在用这个特性时,mktemp命令会返回用来创建临时文件的全路径,而不只是文件名。
创建临时目录
-d选项会告诉mktemp命令来创建一个临时目录而不是临时文件。
记录消息
将输出同时发送到显示器和日志文件,这种做法有时候能够派上用场。你不用将输出重定向两次,只要用特殊的tee命令就行。
tee命令相当于管理的一个T型接口。它将从STDIN过来的数据同时发往两处。一处理是STDOUT,另一处是tee命令行所指定的文件名。
date | tee testfile
默认情况下,tee命令会在每次使用时覆盖输出文件内容。如果你想将数据追加到文件中,必须用-a选项。
e.g. 例子是读取csv文件,然后创建Insert语句将数据插入MySQL数据库。
#!/bin/bash
#read file and create Insert statement for MySQL
outfile='members.sql'
IFS=','
while read lname fname address city state zip
do
cat >> $outfile << EOF
INSERT INTO MEMBERS(lname,fname, address, city, state, zip) values('$lname', '$fname', '$address', '$city', '$state', '$zip');
EOF
done < ${1}
运行脚本:
test23 < members.csv
控制脚本
处理信号
Linux利用信号与运行在系统中的进程进行通信。
重温Linux信号
Linux系统和应用程序可以生成超过30信号。如下列出了常用的。
信号 | 值 | 描述 |
---|---|---|
1 | SIGHUP | 挂起进程 |
2 | SIGINT | 终止进程 |
3 | SIGQUIT | 停止进程 |
9 | SIGKILL | 无条件终止进程 |
15 | SIGTERM | 尽可能终止进程 |
17 | SIGSTOP | 无条件停止进程,但不是终止进程 |
18 | SIGTSTP | 停止或暂停进程,但不终止进程 |
19 | SIGCONT | 继续运行停止的进程 |
默认情况下,bash shell会忽略收到的任何SIGQUIT(3)和SIGTERM(5)信号(正因为这样,交互式shell才不会被意外终止)。但是bash shell会处理收到的SIGHUP(1)和SIGINT(2)信号 。
生成信号
bash shell允许用键盘上的组合键生成两种基本的Linux信号。
- 中断进程
Ctrl+C组合键会生成SIGINT信号,并将其发送给当前在shell中运行的所有进程。
Ctrl+C组合键会发送SIGINT信号,停止shell中当前运行的进程。 - 暂停进程
你可以在进程运行期间暂停进程,而无需终止它。
Ctrl+Z组合键会生成一个SIGTSTP信号,停止shell中运行的任何进程。停止进程跟终止进程不同:停止进程会让程序继续保留在内存中,并能从上次停止的位置继续运行。
可以使用ps命令来查看已停止的作业。
捕获信号
也可以不忽略信号,在信号出现时捕获它们并执行其他命令。trap命令允许你来指定shell脚本要监看并从shell中拦截的Linux信号。如果脚本收到了trap命令中列出的信号,该信号不再由shell处理,而是交由本地处理。命令格式:
trap commands signals
在trap命令行上,你只要列出想要shell执行的命令,以及一组用空格分开的待捕获的信号。你可以用数值或Linux信号名来指定信号。
e.g. 使用trap命令来忽略SIGINT信号,并控制脚本的行为
#!/bin/bash
#Testing signal trapping
trap "echo 'sorry! I have trapped Ctrl-C'" SIGINT
echo This is a test script
count=1
while [ $count -le 10]
do
echho "Loop #$count"
sleep 1
count=$[ $count + 1]
done
echo "This is thhe end of the test script"```
本例中用到的trap命令会在每次检测到SIGINT信号时显示一行简单的文本消息。捕获这些信号会阻止用户用bash shell组合键Ctrl+C来停止程序。
每次使用Ctrl+C组合键,脚本都会执行trap命令中指定的echo语句,而不是处理该信号并允许shell停止该脚本。
捕获脚本退出
除了在shell脚本中捕获信号,你也可以在shell脚本退出时进行捕获。这是在shell完成任务时执行命令的一种简便方法。
要捕获shell脚本的退出,只要在trap命令后加上EXIT信号 就行。
修改或移除捕获
想要在脚本 中的不同位置进行不同的捕获处理,只需要重新使用带有新选项的trap命令。修改了信号捕获之后,脚本处理信号的方式就会发生变化。但如果一个信号是在捕获被修改前接收到的,那么脚本仍然会根据最初的trap命令进行处理。
也可以删除已设置好的捕获。只需要在trap命令与希望恢复默认行为的信号列表之间加上破折号(一个或两个都可以)就行了。
以后台模式运行脚本
后台运行脚本
以后台模式运行shell脚本只需要在命令后加个&符就行了。
当&符放到命令后时,它会将命令和bash shell分离开来,将命令作为系统中的一个独立的后台进程运行。
不过需要注意,当后台进程运行时,它仍然会使用终端显示器来显示STDOUT和STDERR消息。这样脚本的输出就会与shell提示符混杂在一起了。所以最好是将后台运行的脚本 的STDOUT和STDERR重定向。
运行多个后台作业
在非控制台下运行脚本
有时你会想在终端会想在终端会话中启动shell脚本,然后让脚本一直在后台模式运行到结束,即使你退出了终端会话。这可以使用nohup命令来实现。
nohup命令运行了另外一个命令来阻断所有发送给该进程的SIGHUP信号。这会在退出终端会话时阻止进程退出。格式如下:
nohup testshell.sh &
由于nohup命令会解除终端与进程的关联,进程也就不再同STDOUT和STDERR联系在一起。为了保存该命令产生的输出,nohup命令会自动 将STDOUT和STDERR的消息重定向到一个名为nohup.out的文件中。
作业控制
启动,停止,终止以及恢复作业的这些功能统称为作业控制。
查看作业
作业控制中的关键命令是jobs命令。jobs命令允许查看shell当前正在处理的作业。
脚本中使用$$变量来显示Linux系统分配给该脚本的PID。
jobs命令的常用参数:
参数 | 描述 |
---|---|
-l | 列出进程的PID以及作业号 |
-n | 只列出上次shell发出的通知后改变了状态的作业 |
-p | 只列出作业的pid |
-r | 只列出运行中的作业 |
-s | 只列出已停止的作业 |
作业列表中带加号的作业会被当作默认作业。在使用作业控制命令时,如果示在命令行指定任何作业号,该 作业会被当成作业控制命令的操作对象。
重启停止的作业
要以后台模式重启一个作业,可用bg命令加上作业号。
要以前台模式重启作业,可用带有作业号的fg命令。
调整谦让度
在Linux系统中,由shell启动的所有进程的调试优先级默认都是相同的。
调试优先级是个整数值,从-20(最高优先级)到+19(最低优先级)。默认情况下,bash shell以优先级0来启动所有进程。
可以使用nice命令改变优先级
nice命令
在启动命令时只要用nice命令指定优先级别,就可以降低命令的优先级。
nice -n 10 ./testshell.sh > out.out &
renice命令
如需要改变已运行命令的优先级。renice可以允许你指定运行进程的PID来改变它的优先级。
renice -n num -p pid
不过有一些限制:
- 只能对属于你的进程执行renice
- 只能通过renice降低优先级
- root用户可以通过renice来任意调整进程的优先级。
定时运行作业
Linux系统提供了多个在预选时间运行脚本的方法: at命令和cron表。
用at命令来计划执行作业
at命令允许指定Linux系统何时运行脚本。at命令会将作业提交到队列中,指定shell何时运行该作业。at的守护进程atd会双后台模式运行,检查作业队列来运行作业。大多数Linux发行版会在启动时运行此守护进程。
atd守护进程会检查系统上的一个特殊目录(var/spool/at)来获取用at命令提交的作业。默认情况下atd守护进程会每60秒检查一下这个目录。有作业时,atd守护进程会检查作业设置的运行时间。如果时间跟当前时间匹配,atd守护进程就会运行此作业。
- at命令的格式
at [ -f filename] time
如果你指定的时间已经错过,at命令会在第二天的那个时间运行指定的作业。
at命令能识别多种不同的时间格式
- 标准的小时和分钟格式,比如10:15
- AM/PM指示符,比如10:15 PM
- 特定可命名时间,比如now, noon, midnight或者teatime(4 PM)。
除了指定运行作业的时间,也可以通过不同的日期格式指定特定的日期。
- 标准日期格式,比如MMDDYY,MM/DD/YY或DD.MM.YY
- 文本日期,比如Jul 4或Dec 25,加不加年份均可。
- 你也可以指定时间增量
- 当前时间+25 min
- 明天10:15 PM
- 10:15 + 7天
在你使用at命令时,该 作业会被提交到作业队列。作业队列会保存通过at命令提交的待处理作业。针对不同优先级,存在 26种不同的作业队列。作业队列通常用小写字母a-z和大写字母A-Z来指代。作业队列的字母排序越高,作业运行的优先级主小老虎 低(更衰败的nice值)。默认情况下,at的作业会被提交到a作业队列。如果想以更高优先级运行作业,可以用-q参数指定不同的队列字母。
- 获取作业的输出
当作业在Linux系统上运行时,显示器并不会关联到该作业。取而代之的是,Linux系统会将提交该作业的用户的电子邮件地址作为STDOUT和STDERR - 列出等待的作业
atq命令可以查看系统中有哪些作业在等待。 - 删除作业
atrm命令可以删除等待的作业
安排需要定期执行的脚本
- cron时间表
cron时间表采用一种特别的格式来指定作业何时运行。其格式如下:
min hour dayofmnthh month dayofweekk command
- 构建cron时间表
列出已的有时间表:
crontab -l
添加时间表:
crontab -e
- 浏览目录
如果你创建的脚本对精确的执行时间要求不高,用预配置的cron脚本目录会更方便。有4个基本目录:hourly, daily, monthly和weekly 在/etc/下。 - anacron程序
cron程序 的唯一问题是它假定系统是7*24小时运行的。
如果某个作业在cron时间表中安排运行的时间已到,但这个时间Linux系统系统处理于关机状态,那么这个作业就不会被执行。当系统开机时,cron程序不会再去运行那些错过的作业。要解决这个问题,许多Linux发行版还包含了anacron程序。
如果anacron程序知道某个作业错过了执行时间,它会尽快运行该作业。这意味着Linux关机了几天,当它再次开机时,原定在关机期间运行的作业会自动 运行。
anacron程序使用自己的时间表(通常位于/etc/anacrontab)来检查作业目录。
anacron时间表的基本格式和cron时间表略有不同:
period delay identifier command
- period条目定义了作业多久运行一次,以天为单位。
- delay条目会指定系统启动后anacron程序需要等待多少分钟再开始运行错过的脚本。
- command条目包含了run-parts程序和一个cron脚本目录名。run-parts程序负责运行目录中传给它的任何脚本。
- identifier条目是一种特别的非空字符串,如cron-weekly。它用于唯一标识日志消息和错误邮件中的作业。
高级Shell脚本编程
创建函数
基本的脚本函数
在开始编写较复杂的shell脚本时,你会发现自己毛毛虫使用了部分能够执行特定任务的代码。这些代码有时简单,比如显示一条文本消息,或者从脚本用户那里获得一个答案,有时则会比较复杂,需要作为大型处理过程中的一部分被多次使用。
函数是一个脚本代码块,你可以为其命名并在代码中任意位置重用。要在脚本中使用该 代码,只要使用所起的函数名就行了(这个过程称为函数调用)。
创建函数
有两种格式可以用来在bash shell脚本 中创建函数。第一种格式采用function关键字,后跟分配该代码块的函数名。
function funcname {
commands
}
funcname属性定义了赋予函数的唯一名称。脚本中定义的每个函数都必须有一个唯一的名称。
commands是构成函数的一条或多条bash shell命令。
第二种格式更接近于其他编程语言中定义函数的方式。
funcname() {
commands
}
函数名后的空括号表明正在定义的是一个函数。这种格式的命名规则和之前定义shell脚本 函数的格式一样。
使用函数
要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就行了。
返回值
bash shell会把函数当作一个小型脚本,运行结束时会返回一个退出状态码,有3种不同的方法来为函数生成退出码。
默认退出状态码
默认情况下,函数的退出状态码是函数中最后一条命令退出状态码。在函数执行结束后,可以用标准变量$?来确定函数的退出状态码。
使用return命令
bash shell使用return命令来退出函数并返回特定的退出状态码。return命令允许指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来编程设定函数退出状态码。
不过需要注意:
- 函数一结束就取返回值
- 退出状态码必须是0-255
如果在用$?变量提取函数返回值 之前执行了其他命令,函数的返回值就会丢失。
使用函数输出
正如可以将命令的输出保存到shell变量中一样,你也可以对函数同样的处理办法。可以用这种技术来获得任何类型的函数输出,并将其保存到变量中。
result=$(func)
在函数中使用变量
在函数中使用变量时,你需要注意它们的定义方式以及处理方式。
向函数传递参数
bash shell会将函数当作小型脚本来对待。这意味着你可以像普通脚本那样向函数传递参数。
函数可以使用参数环境变量来表示命令行上传给函数的参数。也可以用特殊变量$#来判断传给函数的参数数目。
在函数中处理变量
给shell脚本程序员带来麻烦的原因之一就是变量的作用域。作用域是变量可见的区域。函数中定义的变量与普通变量的作用域不同。也就是说,对脚本 的其他部分而言,它们是隐藏的。
函数使用两种类型的变量:
- 全局变量
- 局部变量
全局变量
全局变量是在shell脚本中任何地方都有效的变量。如果你在脚本的记事本部分定义了一个全局变量。那么可以在函数内读取它的值。类似你在函数内定义了一个全局变量,可以在脚本的主体部分读取它的值。
默认情况下,你在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问。
如果变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值也依然有效。
局部变量
函数内部使用的任何变量都可以被声明成局部变量。要实现这一点只要在变量声明前面加上local关键字就可以了
local variable_name
你也可以在变量赋值语句中使用local关键字
local variable_name=$[ $value + 5]
local关键字保证了变量只局限在该函数中。如果脚本中在该函数之外有同样名字的变量,那么shell将会保持这两个变量的值是分离的。现在你就能很轻松地将函数变量和脚本变量隔离开了,只共享需要共享的变量。
数组变量和函数
向函数传数组参数
向脚本函数传递数组变量的方法会有点不好理解 。将数组变量当作单个参数传递的话,它不会起作用。
如果你试图将数组变量作为函数参数,函数只会取数组变量的第一个值。要解决这个问题,你必须将该数组的值分解成单个的值,然后将这些值作为函数参数使用。
从函数返回数组
从函数里向shell脚本传回数组变量用类似的方法。函数用echo语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。
函数递归
局部函数变量的一个特性是自成体系。除了从脚本 命令行处获得的变量,自成体系的函数不需要使用任何外部资源。
这个特性使得函数可以递归地调用,也就是说,函数可以调用 自己来得到结果。
创建库
使用函数可以在脚本 中省去一些输入工作,但若需要在多个脚本 中使用同一段代码。我们就需要创建函数库文件。bash shell允许创建函数库文件,然后在多个脚本 中引用该库文件。
格式:
. 库文件
在命令行上使用函数
在命令行上创建函数
因为shell会解释用户输入 的命令,所有可以在命令行上直接定义一个函数。有两种方法
一种方法是采用行方式定义函数。
当在命令行上定义函数时, 你必须记得在每个命令后面加个分号,这样shell就能知道 在哪里是命令的起止了。
另一种方法是采用多行方式来定义函数。在定义时,bash会使用次提示符来提示输入更多命令。用这种方法, 你不用在每条命令的末尾放一个分号,只要按下回车键就行。
在函数的尾部使用花括号,shell就会知道你已经完成了函数的定义。
在.bashrc文件中定义函数
- 直接定义函数
- 读取函数文件
图形化桌面环境中的编程脚本
创建文本菜单
shell脚本 菜单的核心是case命令。case命令会根据用户在菜单 上的选择来执行特定命令。
创建菜单布局
- 使用clear清屏
- 使用echo打印菜单项
- 使用read命令读取用户输入。
创建菜单函数
shell脚本 菜单 选项作为一组独立 的函数实现起来更为容易。要做到这一点,你要为每个菜单 选项创建独立的shell函数。
创建shell菜单 脚本 的第一步是决定你希望脚本执行哪些功能,然后将这些功能以函数的形式放在代码中。
通常我们会为还没有实现的函数先创建一个桩函数(stud function)。桩函数是一个空函数或者只有一个echo语句,说明最终这里需要什么内容。这允许你的菜单在你实现某个函数时仍然能正常操作。
添加菜单逻辑
整合shell脚本菜单
e.g…
#!/usr/bash
#simple script menu
functiion diskspace {
clear
df -k
}
function whoseon {
clear
whho
}
functiion memusage {
clear
cat /proc/meminfo
}
function menu {
clear
echo
echo -e "\t\t\tSys Admin Menu\n"
echo -e "\t1. Display disk space"
echo -e "\t2. Display logged on users"
echo -e "\t3. Display memory usage"
echo -e "\t0. Exit program\n\n"
echo -en "\t\tEnter option: "
read -n 1 option
}
while [ 1 ]
do
menu
case $option in
0)
break ;;
1)
diskspace ;;
2)
whoseon ;;
3)
memusage ;;
*)
clear
echo "Sorry, wroong selectiion";;
esac
echo -enn "\n\n\t\t\tHit any key to coontinue"
read -n 1 line
done
clear
使用select命令
select命令只需要一条命令就可以创建出菜单,然后获取输入的答案并自动处理。select命令的格式如下:
select variable in list
do
commands
done
list参数是由空格分隔的文本选项列表,这些列表构成了整个菜单。select命令会将每个列表项显示成一个带编号的选项,然后为选项显示一个由PS3环境变量定义的特殊提示符。
#!/bin/bash
#using select in the menu
function diskspace {
clear
df -h
}
function whoseon {
clear
who
}
function memusage {
clear
cat /proc/meminfo
}
PS3="Enter option:"
select option in "Display disk space" "Display logged on users" "Display memory usage" "Exit program"
do
case $option in
"Exit program")
break ;;
"Display disk space")
diskspace ;;
"Display logged on users")
whoseon ;;
"Display memory usage")
memsage ;;
*)
clear
echo "Sorry, wrong selection";;
esac
done
clear
制作窗口
dialog包
dialog包
dialog命令使用命令行参数来决定生成哪种容器部件。部件是dialog包中容器元素类型术语。dialog包现在运行如下部件类型:
部件 | 描述 |
---|---|
calendar | 提供选择日期的日历 |
checklist | 显示多个选项(其中每个选项都能打开或关闭) |
form | 构建一个带有标签以及文本字段(可以赶写内容)的表彰 |
fselect | 提供一个文件选择容器来浏览选择文件 |
gauge | 显示完成的百分比进度条 |
infobox | 显示一条消息,但不用等待回应 |
inputbox | 提供一个输入文本用的文本表单 |
inputmenu | 提供一个可编辑的菜单 |
menu | 显示可选择的一系列选项 |
msgbox | 显示一条消息,并要求用户选择OK按钮 |
pause | 显示一个进度条来显示暂定期间的状态 |
passwordbox | 显示一个文本框,但会隐藏输入的文本 |
passwordform | 显示一个带标签和隐藏文本字段的表彰 |
radiolist | 提供一组菜单 选项,但只能选择其中一个 |
tailbox | 用tail命令在滚动容器中显示文件的内容 |
tailboxbg | 跟tailbox一样,介是在中运行 |
textbox | 在滚动容器中显示文件的内容 |
timebox | 提供一个选择小时,分钟和秒数的容器 |
yesno | 提供一条带有Yes和No按钮的简单消息 |
要在命令行上指定某个特定的部件,需要使用双破折线格式。
dialog --wiidgett parameters
其中widget是表中的部件名,parameters定义了部件容器的大小以及部件需要的文本
每个dialog部件都提供了两种形式的输出:
- 使用STDERR
- 使用退出状态码
可以通过dialog命令的退出状态码来确定用户选择的按钮。如果选择了Yes或OK按钮,dialog命令会返回退出状态码0.如果选择了Cancel或No按钮,dialog命令会返回退出状态码1.可以用标准$?变量来确定dialog部件中具体选择了哪个按钮。
如果部件返回了数据,比如菜单选择,那么dialog命令会将数据发送到STDERR。可以用标准的bash shell方法来将STDERR输出重定向到另一个文件或文件描述符中。
e.g.
$ dialog --inputbox "Enter you age: " 10 20 2>age.txt
常用的dialog部件
- msgbox部件
它会在窗口中显示一条简单的消息,直到用户单击OK按钮才消失
$dialog -msgboox text height width
text参数是你想在容器中显示的字符串。如果你想在容器顶部放一个标题,也可以用–title参数,后接作为标题的文本。
$ dialog --title titleName --msgbox “This is a msg” 10 20
- yesno部件
yesno部件进一步扩展了msgbox部件的功能,允许用户对容器中显示的问题选择yes或no。
$ dialog --title “Please answer” --yesno “Is this thhing on?” 10 20
echo $?
- inputbox部件
inputbox部件为用户提供了一个简单的文本框区域来输入文本字符串。dialog命令会将文本字符串的值发给STDERR。你必须重定向STDERR来获取用户输入。 - textbox部件
textbox部件是在容器中显示大量信息的极佳办法。它会生成一个滚动容器来显示由参数所指定的文件中的文本。
$ dialog --textbox /etc/passwd 15 45
- menu部件
menu部件允许你来创建我们之前所缺件的文本菜单的窗口版本。只要为每个选项提供一个选择标号和文本就行了。
$ dialog --menu “Sys Admin mennu” 20 300 10 1 “Display diskk space” 2 “Display users” 3 “Display memory usage” 4 “Exit” 2>test.txt
6… fselect部件
dialog选项
除了标准部件,还要以在dialog命令中定制很多不同的选项。
选项 | 描述 |
---|---|
–add-widget | 继续下个对话框,直到按下Esc或Cancel按钮 |
–aspect ratio | 指定容器宽度和高度的宽高比 |
–backtitle title | 指定显示在屏幕顶部背景上的标题 |
–begin x y | 指定容器左上角的起始位置 |
–cancel-label label | 指定Cancel按钮的替代标签 |
–clear | 用默认的对话背景来清空屏幕内容 |
–colors | 在对话文本中嵌入ANSI色菜编码 |
–cr-wrap | 在对话文本中允许使用换行符并强制换行 |
–create-rc file | 将示例配置文件的内容复制到指定的file文件中 |
–defaultno | 将yes/no对话框的默认答案设为No |
–default-item string | 设定复选列表,表单或菜单 对话中的默认项 |
–exit-label label | 指定Exit按钮的替代标签 |
–extra-buton | 在OK按钮和Cancel按钮之间显示一个额外按钮 |
–extra-label label | 指定 额外按钮的替代标签 |
–help | 显示dialog命令的帮助信息 |
–help-button | 在OK按钮 和Cancel按钮后显示一个Help按钮 |
–help-label label | 指定Help按钮的替代标签 |
–help-status | 当选定Help按钮后,在帮助信息后写入多选列表,单选列表或表彰信息 |
–ignore | 忽略dialog不能识别的选项 |
–input-fd fd | 指定 STDIN之外的另一个文件描述符 |
–insecure | 在password部件 中键入内容时显示星号 |
–item-help | 为多选列表,单选列表或菜单中的每个标号在屏幕的底部添加一个帮助栏 |
–keep-window | 不要清除屏幕上显示过的部件 |
–max-input size | 指定输入的最大字符串长度。默认为2048 |
–nocancel | 隐藏Cancel按钮 |
–no-collapse | 不要将对话文本中的制表符转换成空格 |
–no-kill | 将tailboxbg对话放到后台,并禁止该进程的SIGHUP信号 |
–no-label label | 为No按钮指定替代标签 |
–no-shadow | 不要显示对话容器的阴影效果 |
–ok-label label | 指定OK按钮的替代标签 |
–output-fd fd | 指定除STDERR之外的另一个输出文件描述符 |
–print-maxsize | 将对话容器的最大尺寸打印到输出中 |
–print-size | 将每个对话容器的大小打印到输出中 |
–separate-output | 一次一行地输出checklist部件 的结果,不使用引号 |
–separator string | 指定 用于分隔部件输出的字符串 |
–separate-widget string | 指定用于分隔部件输出的字符串 |
–shadow | 在每个容器的右下角绘制阴影 |
–single-quoted | 需要时对多选列表的输出采用单引号 |
–sleep sec | 在处理完对话容器之后延迟指定的秒数 |
–stderr | 将输出发送到STDERR |
–stdout | 将输出发送到STDOUT |
–tab-correct | 将制表符转换成空格 |
–tab-len n | 指定一个制表符占用的空格数(默认为8) |
–timeout sec | 指定无用户输入 时,sec秒后退出并返回错误代码 |
–title title | 指定对话窗口的标题 |
–trim | 从对话文本中删除前导空格和换行符 |
–visit-items | 修改对话窗口中制表符停留位置,使其包括选项列表 |
–yes-label label | 为Yes按钮指定替代标签 |
在脚本中使用dialog命令
在脚本中使用dialog需要注意:
- 如果有cancel或No按钮,检查dialog命令的退出状态码
- 重定向STDERR来获得输出值
使用图形
KDE环境
KDE图形化环境默认包含kdialog包
GNOME环境
GNOME图形化环境支持两种流行的可生成标准容器的包:
- gdialog
- zenity
初识sed和gawk
文本处理
sed编辑器
sed编辑器被称作流编辑器(stream editor),和普通的交互式文本编辑器恰好相反。
sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个文本文件中。sed编辑器会执行下列操作。
- 一次从输入中读取一行数据。
- 根据所提供的编辑器命令匹配数据
- 按照命令修改流中的数据。
- 将新的数据输出到STDOUT
在流编辑器将所有命令与一行数据匹配完毕后,它会读取下一行数据并重复这个过程。在流编辑器处理完流中的所有数据行后,它就会终止。
由于命令是按顺序逐行给出的,sed编辑器只需要对数据流进行一遍处理就可以完成编辑操作。
sed命令的格式如下
sed options script file
选项允许你修改sed命令的行为,可以使用的:
选项 | 描述 |
---|---|
-e script | 在处理输入时,将script中指定的命令添加到已有的命令中 |
-f file | 在处理输入时,将file中指定的命令添加到已有的命令中 |
-n | 不产生命令输出,使用print命令来完成输出 |
script参数指定了应用于流数据上的单个命令。如果需要用多个命令,要么使用-e选项在命令行中指定,要么使用-f选项在单独的文件中指定。
- 在命令行定义编辑器命令
默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。这样你可以直接将数据通过管道输入sed编辑器处理。
e.g.
echo “This is a test” | sed ‘s/test/big test/’
This is a big test
重要的是,要记住,sed编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到STDOUT。
- 在命令行使用多个编辑器命令
要在sed命令行上执行多个命令时,只要用-e选项就可以了。
e.g.
sed -e ‘s/brown/green/; s/dog/cat/’ data1.txt
两个命令都作用到文件中的每行数据上。命令之间必须用分号隔开,并且在命令末尾和分号之间不能有空格。
如果不想用分号,也可以用bash shell中的次提示符来分隔命令。只要输入 第一个单引号标示出sed程序脚本的起始(sed编辑器命令列表),bash会继续提示你输入更多的命令,直到输入了标示结束的单引号。
e.g.
sed -e ’
s/brown/green/
s/fox/elephant/
s/dog/cat/’ data.txt
必须记住,要在封尾单引号所在行结束命令。bash shell一旦发现了封尾的单引号,就会执行命令。开始后,sed命令就会将你指定的每笨命令应用到文本谁的中的每一行上。
- 从文件中读取编辑器命令
最后,如果有大量要处理的sed命令,那么将它们放进一个单独的文件中通常会更方便一些。可以在sed命令中用-f选项来指定文件。
e.g.
sed -f script.sed data.txt
在sed文件中,不用在每条命令后面放一个分号,sed编辑器知道每行都是一条单独的命令。跟在命令行输入命令一样。
gawk程序
gawk能提供一个类编程环境来修改和重新组织文件中的数据。
gawk程序是Unix中的原始awk程序 的GNU版本。在gawk编程语言中,你可以做正面的事情:
- 定义变量来保存数据
- 使用算术和字符串操作符来处理数据
- 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑
- 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。
gawk程序的报告生成能力通常用来从大文本文件中提取数据元素,并将它们格式化成可读的报告。其中最完美的例子就是格式化日志文件。
- gawk命令格式
gawkk options program file
可用选项:
选项 | 描述 |
---|---|
-F fs | 指定行中划分数据字段的字段分隔符 |
-v var=value | 定义gawk程序中的一个变量及其默认值 |
-mf N | 指定要处理的数据文件中的最大字段值 |
-mr N | 指定数据文件中的最大数据行数 |
-W keyword | 指定gawk的兼容模式或警告等级 |
命令行选项提供了一个简单的途径来定制gawk程序的功能。
- 从命令行读取程序脚本
gawk程序脚本用一对花括号来定义。你必须将脚本命令放到两个花括号({})中。
由于gawk命令行假定脚本是单个文本字符串,你还必须将脚本放到单引号中。
e.g.
gawk ‘{print “Hello World!”}’
要终止这个gawk程序,你必须表明数据流已经结束了。bash shell提供了一个组合键来生成EOF(End-of-File)字符。Ctrl+D组合键会在bash中产生一个EOF字符。这个组合键能够终止gawk程序并返回到命令行界面提示符下。
- 使用数据字段变量
gawk的主要特性之一是其处理文本文件中数据的能力。它会自动给一行中的每个数据元素分配一个变量。
-$0: 代表整个文本行
- $1:代表文本行中的第1个数据字段。
…
在文本行中,每个数据字段字段都是通过字段分隔符划分的。gawk在读取一行文本时,会用预定义的字段分隔符划分每个数据字段。gawk中默认的字段分隔符是任意的空白字符(例如空格或制表符)。
- 在程序脚本 中使用多个命令
gawk编程语言允许你将多条命令组合成一个正常的程序。要在命令行上有程序脚本中使用多条命令,只要在命令之间放个分号即可。
e.g.
echo “My name is Rich” | gawk ‘{$4=“Christine”; print $0}’
My name is Christine
第一条命令会给字段变量$4赋值。第二条命令会打印整个数据字段。
- 从文件中读取程序
跟sed编辑器一样,gawk编程器允许将程序存储到文件中,然后再在命令行中引用。
e.g.
cat script.gawk
{print $1 "'s homedirectory is " $6}
gawk -F: -f scrippt.gawk /etc/passwd
- 在处理数据前运行脚本
gawk还允许指定程序脚本何时运行。默认情况下,gawk会从输入中读取一行文本,然后针对该行的数据执行程序脚本 。有时可能需要在处理数据前运行脚本,比如为报告创建标题。BEGIN关键字就是用来做这个的。它会强制gawk在读取数据前执行BEGIN关键字后指定的程序脚本 。
e.g.
gawkk ‘BEGIN {print “Hello World!”}’
- 在处理数据后运行脚本
与BEGIN关键字类似,END关键字允许你指定一个程序脚本,gawk会在读完数据后执行它。
e.g.
gawk ‘BEGIN {print "The data3 File Contents: "}
{print $0}
END {print “End of File”}’ data3.txt
在脚本中除了使用-F还可以使用叫作FS的特殊变量指定分隔符。
sed编程基础
成功使用sed编辑器的关键在于掌握其各式各样的命令和格式。
更多的替换选项
s命令(substitute):替换
- 替换标记
替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处,要让替换命令替换一行中不同地方出现的文本必须使用替换标记。替换标记会在替换命令字符串之后设置。
s/pattern/replaccement/flags
有4种可用的替换标记:
- 数字: 表明新文本将替换第几处模式匹配的地方
- g: 表明新文本将会替换所有匹配的文本
-p: 表明原先行的内容要打印出来
-w file:将替换的结果写到文件中
sed ‘s/test/trial/w test.txt’ data.txt # w替换标记会产生输出到test.txt文件
- 替换字符
有时你会在文本字符串中遇到一些不太方便在替换模式中使用的字符。如:正斜线。要解决这个问题,sed编辑器允许选项其他字符来作为替换命令中的字符串分隔符。
e.g. 使用感叹号做为分隔符
sed ‘s!/bin/bash!/bin/zsh!’ /etc/passwd
使用地址
默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须用行寻址。在sed编辑器中有两种形式的行寻址:
- 以数字形式表示行区间
- 用文本模式来过滤出行
两种形式都使用相同的格式来指定地址:
[address] command
也可以将特定地址的多个分组:
address {
command1
command2
command3
}
- 数字方式 的行寻址
e.g.
sed ‘2s/dog/cat/’ data1.txt #只替换第二行
sed ‘2,3s/dog/cat/’ data1.txt #替换2到3行
sed ‘2, $s/dog/cat/’ data1.txt #替换2到最后一行
- 使用文本模式过滤器
sed允许指定文本模式来过滤出命令要作用的行,命令格式如下:
/pattern/command
必须用正斜线将要指定的pattern封起来。sed编辑器会将该 命令作用到包含指定文本模式的行上。
e.g.
sed ‘/root/s/bash/zsh/’ /etc/passwd #替换root用户的默认shell
sed编辑器在文本模式中采用了一种称为正则表达式的特性来帮助创建匹配模式。
- 命令组合
如果需要在单选上执行多条命令,可以用花括号将多条命令组合在一起。sed编辑器会处理地址行处列出的每条命令。
e.g.
sed ‘2, ${
s/foox/elephant/
s/dog/cat/
}’ data.txt
删除行
删除命令d,会删除匹配指定寻址模式的所有行。如果忘记加入寻址模式的话,流中的所有文本行都会被删除。
- 通过区间指定
sed ‘2, 5d’ data.txt
- 通过模式匹配删除
sed ‘/number 1/d’ data.txt
记住sed编辑器不会修改原始文件,你删除的行只是从sed编辑器的输出中消失了。原始文件仍然包含那些“删除掉的”行
插入了附加文本
sed编辑器允许向数据流 插入附加 文本行。
- 插入(insert)命令(i)会在指定行前增加一个新行;
- 附加(append)命令(a)会在指定行后增加一个新行。
它们不能在单个命令行上使用。你必须指定是要将行插入还是附加 到另一行。格式如下:
sed ‘[address]command
new line’
new line中的文本将会出现在sed编辑器输出中你指定的位置。
e.g.
echo “Test Line 2” | sed ‘i\Test Line 1’
sed ‘3i
This is an inserted line.’ data.txt #数据会插入到数据流的第三行
修改行
修改(change)命令(c)允许你修改数据流中事先 文本的内容。
同样可以使用行号模式和文本模式也寻址
e.g.
sed ‘3c
This is a changed line of text.’ data.txt
sed ‘/number 4/c
This is a change line of txt .’ data.txt
转换命令
转换(transform)命令(y)是唯一可以处理单个字符的sed编辑器命令。格式如下:
[address]y/inchars/outchars/
转换命令会对inchars和outchars值 进行一对一的映射。如果inchars和outchars的长度不同,则sed编辑器会产生一条错误消息。e.g.
sed ‘y/123/789/’ datta.txt
转换命令是个全局命令,也就是说,它会在文本行中找到的所有指定字符自动 进行转换,而不会考虑它们出现的位置。
回顾打印
有3个命令可以用来打印数据流中的信息:
- p命令
- 等号(=)命令用来打印行号
- 小写的L命令用来列出行
- 打印行
echo “thhis is a test” | sed ‘p’
sed -n ‘/number 3/p’ data.txt
在命令行上用-n选项,你可以禁止输出其他行只打印包含匹配文本模式的行。
sed -n ‘2,3p’ data.txtt
如果需要在修改之前查看行,也可以使用打印命令,比强替换或修改命令一起使用。
e.g.
sed -n ‘/3/{
p
s/line/test/p
}’ data.txt #sed命令会查找包含数字3的行,然后执行两条命令。
- 打印行号
等号命令会打印行在数据流中的当前行号。
sed ‘=’ data.txtt
- 列出行
列出(list)命令(l)可以打印数据流中的文本和不可打印的ASCII字符。
e.g.
sed -n ‘l’ data.txt
使用sed处理文件
1.写入文件
w命令用来向文件写入行。格式如下:
[adddress]w filename
filename可以使用相对路径 或绝对 路径,但不管是哪种,运行sed编辑器的用户都必须有文件的写权限。
e.g.
sed ‘1,2w test.txt’ data.txtt #将data.txt中的前两行写入test.txt
- 从文件读取数据
读取(read)命令(r)允许你将一个独立 文件中的数据插入到数据流中。格式如下:
[address]r filename
filename参数指定了数据文件的绝对路径 或相对路径 。你在读取命令中使用地址区间,只能指定单独一个行号或文本模式地址。sed编辑器会将文件中的文本插入到指定 地址后。
e.g.
sed ‘3r data1.txt’ data2.txt #会将data1.txt中的数据插入data2的第三行后。
正则表达式
在脚本 中成功运用sed编辑器和gawk程序的着急在于熟练使用正则表达式。
什么是正则表达式
定义
正则表达式的类型
正则表达式是通过正则表达式引擎(regular expression engine)实现的。正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行文本匹配
在Linux中,有两种流行的正则表达式引擎:
- POSIX基础正则表达式(basic regular expression.BRE)引擎
- POSIZ扩展正则表达式(extended regular expression, ERE)引擎
定义BRE模式
纯文本
特殊字符
正则表达式识别的特殊字符包括:
.*[]^${}+?|()
如果需要某个特殊字符作为文本字符,就必须转义。在转义特殊字符时,你需要在它前面加一个特殊字符来告诉正则表达式引擎应该将接下来的字符当作普通的文本字符。这个特殊字符就是反斜线(\)。
锚字符
- 锁定在行首
脱 字符(^)定义从流中文本行的行首开始的模式。如果模式出现在行首之外的位置,正则表达式模式则无法匹配。 - 锁定在行尾
特殊字符$定义了行尾锚点。 - 组合锚点
点号字符
特殊字符点号用来匹配除换行符之外的任意单个字符。
字符组
使用方括号来定义一个字符组。方括号里包含所有你希望出现在该 字符组中的字符。
排除型字符组
在字符组的开头加一个脱字符,就可以反转字符组的作用。寻找组中没有的字符。
区间
可以使用单破折线符号在字符组中表示字符区间。
特殊的字符组
BRE特殊字符组
组 | 描述 |
---|---|
[[:alpha:]] | 匹配任意字母字符,不管是大写还是小写 |
[[:allnum:]] | 匹配任意字母数字字符0-9, a-z或A-Z |
[[:blank:]] | 匹配空格或制表符 |
[[:diigit:]] | 匹配0-9之间的数字 |
[[:lower:]] | 匹配小写字母字符 |
[[:print:]] | 匹配伴音可打印字符 |
[[:punct:]] | 匹配标点符号 |
[[:space:]] | 匹配任意空白字符:空格,制表符,ML, FF, VT和CR |
[[:upper:]] | 匹配任意大写字母字符 |
可以在正则表达式模式中将特殊字符组像普通字符组一样使用。
星号
在字符后面放置昨号表明该 字符那也得在匹配模式的文本中出现0次或多次
扩展正则表达式
POSIX ERE模式包括了一些可供Linux应用和工具使用的额外符号 。gawk程序能够识别ERE模式,但sed编辑器不能。
问号
问题类似于星号,表明前面的字符可以出现0次或1次。
加号
表明前面的字符可以出现1次或多次。
使用花括号
花括号允许你为可重复的正则表达式指定一个上限。这通常称为间隔。可以用两种格式来指定区间
- m: 正则表达式准确出现m次
- m,n:正则表达式至少出现m次,至多出现n次。
管道符号
管道符号允许你在检查数据流时,用逻辑OR方式指定正则表达式引擎要用的两个或多个模式。如果任何一个模式匹配了数据流文本,文本就通过测试。
表达式分组
正则表达式也可以用圆括号分组。当你将正则表达式模式分组时,该分组会被视为一个标准字符。可以像对普通字符一样给该组使用特殊字符。
sed进阶
多行命令
sed编辑器包含了三个可用来处理多行文本的特殊命令。
- N: 将数据流中的下一行加进来创建一个多行组来处理
- D: 删除多行组中的一行
- P: 打印多行组中的一行。
next命令
- 单行的next命令
e.g.
sed ‘/header/{n; d}’ data.txt # 删除含有header的行的下一行。
- 合并文本行
多行版本的next命令(用大写的N)会将下一文本行添加到模式空间中已有的文本后。这样的作用是将数据流中的两个文本行合并到同一个模式空间中 。文本用换行符分隔。
e.g.
sed ‘/first/{N ; s/\n/ /}’ data.txt #查询含有单词first的那行文本。找到该行后,它会用N命令将下一行合并到那行,然后用替换命令s将拣选符替换成空格。
多行删除命令
e.g.
sed ‘N ; /Systemm\nAdministrator/d’ datta.txt #会删除合并后的两行内容
sed ‘N ; /System\nAdministrator/D’ datta.txt # 会删除模式空间中的第一行。
多行打印命令
多行打印命令(P)没用了同样的方法。它只打印多行模式空间中的第一行。
保持空间
模式空间(pattern space)是一块活跃的缓冲区,在sed编辑器执行命令时它会保存待检查的文本。但它并不是sed编辑器保存文本的唯一空间。
sed编辑器有另一块称作保持空间(hold space)的缓冲区域。有5条命令可用来操作保持空间:
命令 | 描述 |
---|---|
h | 将模式空间复制到保持空间 |
H | 将模式空间附加到保持空间 |
g | 将保持空间复制到模式空间 |
G | 将保持空间附加到模式空间 |
x | 交换模式空间和保持 空间的内容 |
排除命令
感叹号命令(!)用来排除(negate)命令,也就是说原本会起作用的起作用。相当于取反的作。
改变流
分支
分支(branch)命令b的格式如下:
[address]b [label]
adddress参数决定了哪些行的数据会触发分支命令。label参数定义了要跳转到的位置。如果没有加label参数,跳转命令会跳转到脚本 的结尾。
sed ‘{/first/b jump1 ; s/This is the /No jump on/
:jump1
s/This is the /Jump here on/}’ data.txt
e.g.
echo “This, is , a test, to, remove, commands.” | sed -n ‘{
:atart
s/,//1p
/,/b tart
}’
分支命令会在行中有逗号的情况下跳转。在最后一个逗号被删除后,分支命令不会再执行,脚本也就能正常停止了。
测试
格式:
[address]t [label]
e.g.
sed ‘{
s/firstmatched/
t
s/This is the /No match on/
}’ data.txt
第一替换命令会查找模式文本firstt。如果匹配了行中的模式,它就会替换文本,而且测试命令会路过后面的替换命令。如果第一个替换命令未能匹配模式,第二个替换命令就会被执行。
模式替代
&符号
&符号可以用来代表替换命令中的匹配的模式。不管模式匹配的是什么样的文本,你都可以在替代模式中使用&符号来使用这段文本。
e.g.
echo “The cat sleeps in his hat.” | sed ‘s/.at/"&"/g’
The “cat” sleeps in his “hat”.
替代单独的单词
sed编辑器用圆括号来定义替换模式中的子模式。你可以在替代模式中使用特殊字符来引用每个子模式。替代字符由反斜线和数字组成。数字表明子模式的位置。sed编辑器会给第一个子模式分配字符\1,给第二个子模式分配字符\2,依此类推。
e.g.
echo “The System Administrator manuall” | sed ’
s/(System) Administrator/\1 User’
这个替换命令用一对圆括号将单词System括起来,将其标示为一个子模式。然后它在替代模式中使用\1来提取第一个匹配的子模式。
在脚本中使用sed
创建sed实用工具
加倍行间距
sed ‘$!G’ data.txt
对可能 含有空白行的文件加倍行间距
sed ‘/^$/d ; $!G’ data.txt
给文件中的行编号
sed ‘=’ data.txt | sed ‘N; s/\n/ /’
打印末尾行
sed -n ‘$p’ data.txt
删除行
删除数据流中不需要的空白行。
- 删除连续的空白行
sed ‘/./,/^$/!d’ data.txt
- 删除开头的空白行
sed ‘/./,$!d’
- 删除结尾的空白行
sed ‘{
:start
/^\n*KaTeX parse error: Expected '}', got 'EOF' at end of input: /{d; N; b start }
}’
- 删除HTML标签
sed ‘s/<.*>//g’ data.txt
gawk进阶
使用变量
所有编程语言共有的一个重要特性是使用变量来存取值。gawk编程语言支持两种不同类型的变量:
- 内建变量
- 自定义变量
内建变量
- 字段和记录分隔符变量
数据字段变量:允许你使用美元符号和字段在该 记录中的位置修士来引用记录对应的字段。如第一个:$1。
数据字段由字段分隔符来划定的。默认情况下,字段分隔符是一个空白字符,也就是空格符或制表符。我们在命令行下可以使用-F或者gawk程序中使用特殊的内建变量FS来更改字段分隔符。
gawk数据字段和记录变量:
变量 | 描述 |
---|---|
FILEDWIDTHS | 由空格分隔的一列数字,定义了每个数据字段确切宽度 |
FS | 输入字段分隔符 |
RS | 输入记录分隔符 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
- 数据变量
更多的gawk内建变量:
变量 | 描述 |
---|---|
ARGC | 当前命令行参数个数 |
ARGIND | 当前文件在ARGV中的位置 |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字的转换格式(参见printf语句),默认值为%.6g |
ENVIRON | 当前Shell环境变量及其值组成的关联数组 |
ERRNO | 当读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | 用作GAWK输入数据的数据文件的文件名 |
FNR | 当前数据文件中的数据行数 |
IGNORECASE | 设成非零值时,忽略gawk命令中出现的字符串的字符大小写 |
NF | 数据文件中的字段总数 |
NR | 已处理的输入记录数 |
OFMT | 数字的输出格式,默认值为%.6g |
RLENGTH | 由match函数所匹配的子字符串的长度 |
RSTART | 由match函数所匹配的子字符串的起始位置 |
说明:跟shell变量不同,在脚本 中引用gawk变量时,变量名前不加美元符。
自定义变量
gawk自定义变量名可以是任意数目 的字母,数字和下划线,但不能以数字开头。而且区分大小写。
- 在脚本 中给变量赋值
在gawk程序 中给变量赋值跟在shell脚本 中赋值类似,都用赋值语句。
e.g.
gawk ’
BEGIN{
testing=“This is a test”
print testing
}’
This is a test
- 在命令行上给变量赋值
处理数组
Gawk使用关联数组提供数组功能 。
定义数组变量
可以用标准赋值语句 来定义 数组变量。格式如下:
var[index] = element
遍历数组变量
可以使用for语句的一种特殊形式。
for (var in arrayy) {
print "Index: ", test, " - Value: ", var[test]
}
删除数组变量
delete array[index]
使用模式
正则表达式
在使用正则表达式时,正则表达式必须出现在它要控制的程序脚本 的左花括号前。
gawk ‘BEGIN{FS=","} /11/{print $1}’ data
正则表达式/11/匹配了数据字段中含有字符串11的记录。
匹配操作符
匹配操作符(matching operator)允许将正则表达式限定在记录中的特定数据字段。匹配操作符的波浪线(~)可以指定匹配操作符,数字字段变量以及要匹配的正则表达式。
e.g.
gawk ‘BEGIN{FS=","} $2 ~ /^data2/{print $0}’ data
匹配操作符会用正则表达式/^data2/来比较第二个数据字段。
数学 表达式
除了正则表达式,你也可以在匹配模式中用数学表达式。
e.g.
gawkk -F: ‘$4==0{print $1}’ /etc/passwd
结构化命令
if语句
gawk编程语言支持标准的if-then-else格式的if语句。格式:
if (condition) statment
e.g.
gawk ‘{ if ($1 > 20) { x = $1 *2
print x
}
}’ datta
while语句
格式:
while (condition) {
statements
}
do-while语句
格式:
do {
stattements
} while (conditiion)
for语句
格式:
for( variable asssignmennt; coondition; iteration process)
格式化打印
gawk中的printf命令跟C语言的用法一致,格式如下:
printf “format string”, var1, var2 …
格式化指定符采用如下格式:
%[modifier]control-letter
其中control-leter是一个单字符代码,用于指明显示什么类型的数据,而modifier则定义了可选的格式化特性。
格式化指定字符的控制字母表:
控制字母 | 描述 |
---|---|
c | 将一个数作为ASCII字符显示 |
d | 显示一个整数值 |
i | 显示一个整数值(跟d一样) |
e | 用科学计数法显示一个数 |
f | 显示一个浮点数 |
g | 用科学计数法或浮点数显示(选择较短的格式) |
o | 显示一个八进制数 |
s | 显示一个文本字符串 |
x | 显示一个十门进制数 |
X | 显示一个十六进制值,但用大写字母A-F |
除了控制字母外,还有3种修饰符可以用来进一步控制输出。
- widthh: 指定输出字段最小宽度的数字值。如果输出短于这个值 ,printf会将文本右对齐,并用空格进行填充。如果输出比指定的宽度还要长,则按照实际长度输出。
- prec:这是一个数字值,指定浮点数中小数点后面位数,或者文本字符串显示的最大字符数。
- -(减号): 指明在向格式化空间中放入数据时采用左对齐而不是右对齐。
内建函数
gawk提供了不少内置函数,可进行一些常见的数学,字符串以及时间函数运算。
数学函数
函数 | 描述 |
---|---|
atan2(x, y) | x/y的反正切, x和y以弧度为单位 |
cos(x) | x的余弦,x以弧度为单位 |
exp(x) | x的指数函数 |
int(x) | x的整数部分,取靠近零一侧的值 |
log(x) | x的自然对数 |
randd() | 比0大比1小的随机浮点数 |
sin(x) | x的正统,x以弧度为单位 |
sqrt(x) | x的平方根 |
srand(x) | 为计算随机数指定 一个种子 值 |
除了标准数学函数外,gawk还支持一些按位操作数据的函数
函数 | 描述 |
---|---|
and(v1, v2) | 执行值v1和v2的按位运算 |
compl(vall) | 执行val的补位运算 |
lshift(val,count) | 将值val左移count位 |
or(v1, v2) | 执行值v1和v2的按位或运算 |
rshift(val, count) | 将值val右移count位 |
xor(v1, v2) | 执行值v1和v2的按位异或运算 |
字符串函数
函数 | 描述 |
---|---|
asort(s [,d]) | 将数组s按数据元素值排序。索引值 会被替换成的排序顺序的连续数字。另外,如果指定了d,则排序后的数组会存储在数组d中 |
asorti(s [,d]) | 将数组s按索引值排序。生成的数组会将作为数据元素值,用连续数字索引来表明排序顺序。另外如果指定了d,排序后的数组会存储在数组d中 |
gensub(r,s,h [,t]) | 查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果h是一个以g或G开头的字符串,就用s替换掉匹配的文本。如果h是一个数字,它表示替换掉第h处r匹配的地方 |
gsub(r, s [,t]) | 查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果找到了,就全部替换成字符串s |
index(s,t) | 返回字符串t在字符串s中的索引值,如果没找到的话就返回0 |
length([s]) | 返回字符串s的长度,如果没有指定的话,返回$0的撒谎 |
match(s, r [,a]) | 返回字符串s中正则表达式r出现位置的索引。如果指定了数组a,它会存储s中匹配正则表达式的那部分 |
split(s, a [,r]) | 将s用FS字符或正则表达式r(如果指定了的话)分开放到数组a中。返回字段的总数. |
sprintf(format, variables) | 用提供的format和variables返回一个类似于printf输出的字符串 |
sub(r, s [,t]) | 在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处理匹配。 |
substr(s, i [,n]) | 返回s中从索引值i开始的n个字符组成的子字符串。如果未提供n,则返回s剩下的部分 |
toloweer(s) | 将s中的所有字符转换成小写 |
tooupper(s) | 将s中的所有字符转换成大写 |
时间函数
函数 | 描述 |
---|---|
mktiime(datesppec) | 将一个按YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳值 |
strftime(format [,timestamp]) | 将当前时间的时间戳或tiimestammp(如果提供了的话)转化格式化日期(采用shell函数date()的格式) |
systime() | 返回当前时间的时间戳 |
自定义函数
要定义自己的函数,必须用function关键字。
function name([variables]) {
statements
}
函数名必须能够唯一标识函数。
使用自定义函数
在定义函数时,它必须出现在所有代码块之前(包括BEGIN代码块)。它有助于将函数代码与gawk程序的其他部分分开。
创建函数库
gawk提供了一种途径来将多个函数放到一个库文件中,这样你就能在所有的gawk程序中使用了。
首先,你需要创建一个存储所有gawk函数的文件
使用时间需要使用-f命令行参数来使用它们。
使用其它Shell
dash shell
zsh shell
创建实用的脚本
编写简单的脚本实用工具
创建与数据库、Web及电子邮件相关的脚本
一些小有意思的脚本
附录
A1. bash命令快速指南
命令 | 描述 |
---|---|
: | 扩展参数列表,执行重定向操作 |
. | 读取并执行指定文件中的命令(在当前shell环境中) |
alias | 为指定命令定义一个别名 |
bg | 将作业以后台模式运行 |
bind | 将键盘序列绑定到一个readline函数或宏 |
break | 退出for,while,selecct或until循环 |
builtin | 执行指定的shell内建命令 |
caller | 返回活动子函数调用 的上下亠 |
cd | 将当前目录切换为指定的目录 |
command | 执行指定的命令,无需进行通常的shell查找 |
compgenn | 为指定单词生成可能的补全匹配 |
complete | 显示指定的单词是如何补全的 |
compopt | 修改指定单词的补全选项 |
continue | 继续执行for, while,select或until循环的下一次迭代 |
declare | 声明一个变量或变量类型 |
dirs | 显示当前存储目录的列表 |
disown | 从进程作业表中删除指定的作业 |
echo | 将指定字符串输出到STDOUT |
enable | 启用或禁用指定的内建shell命令 |
eval | 将指定的参数拼接成一个命令,然后再执行该命令 |
exec | 用指定命令替换shell进程 |
exit | 强制shell以指定的退出状态码退出 |
export | 设置子shell进程可用的变量 |
fc | 从历史记录中选择命令列表 |
fg | 将作业以前台模式运行 |
getopts | 分析指定的位置参数 |
hash | 查找并记住指定命令的全路径名 |
help | 显示帮助文件 |
history | 显示命令历史记录 |
jobs | 列出活动作业 |
kill | 向指定的进程ID发送一个系统信号 |
let | 计算一个数学表达式中的每个参数 |
local | 在函数中创建一个作用域受限的变量 |
logout | 退出登录shell |
mapfile | 从STDIN读取数据行,并将其加入索引数组 |
popd | 从目录栈中删除记录 |
printf | 使用格式化字符串显示文本 |
pushd | 向目录栈添加一个目录 |
pwd | 显示当前工作目录的路径名 |
read | 从STDIN读取一行数据并将其赋给一个变量 |
readarray | 从STDIN读取数据行并将其放入索引数组 |
readonly | 从STDIN读取一行数据并将其赋给一个不可修改的变量 |
return | 强制函数以某个值退出,这个值可以被调用脚本提取 |
set | 设计并显示环境变量的值和shell属性 |
shift | 将位置参数依次向下降一个位置 |
shopt | 打开/关闭控制shell可选 行为的变量值 |
source | 读取并执行指定文件中的命令 |
suspend | 暂停shell的执行,直到收到一个SIGCONT信号 |
test | 基于指定条件返回退出状态码0或1 |
times | 显示累计的用户和系统时间 |
trap | 如果收到了指定的系统信号,执行指定的命令 |
type | 显示指定的单词如果作为命令将会如何被解释 |
typeset | 声明一个变量或变量类型 |
ulimit | 为系统用户设置指定的资源的上限 |
umask | 为新建的文件和目录设置默认权限 |
unalias | 删除指定的别名 |
unset | 删除指定的环境变量或shell属性 |
wait | 等待指定的进程完成,并返回退出状态码 |
A2. 常见的bash命令
命令 | 描述 |
---|---|
bzip2 | 采用Burrows-Wheeler块排序文本压缩算法和霍夫曼编码进行压缩 |
cat | 列出指定文件的内容 |
chage | 修改指定系统用户账户的密码过期日期 |
chfn | 修改指定用户账户的备注信息 |
chgrp | 修改指定文件或目录的默认属组 |
chmod | 为指定文件或目录修改系统安全权限 |
chown | 修改指定文件或目录的默认发证 |
chpasswd | 读取一个包含登录名/密码的文件并更新密码 |
chsh | 修改指定用户账户的默认shell |
clear | 从终端仿真器或虚拟控制台终端删除文本 |
compress | 最初的Unix文件压缩工具 |
coproc | 在后台模式中生成子shell,并执行指定的命令 |
cp | 将指定文件复制到另一个位置 |
crontab | 初始化用户的crontable对应的编辑器(如果允许的话) |
cut | 删除文件行中指定的位置 |
date | 以各种格式显示日期 |
df | 显示所有挂载设备的当前磁盘空间使用情况 |
du | 显示指定文件路径的磁盘使用情况 |
emacs | 调用emacs文本编辑器 |
file | 查看指定文件的文件类型 |
find | 对文件进行递归查找 |
free | 查看 系统上可用的和已用的内存 |
gawk | 使用编程语言命令的流编辑器 |
grep | 在文件中查找指定的文本字符串 |
gedit | 调用 GNOME桌面编辑器 |
getopt | 解析命令选项(包括长格式选项) |
groups | 显示指定用户的组成员关系 |
groupadd | 创建新的系统组 |
groupmod | 修改已有的系统级 |
gzip | 采用Lempel-Ziv编码的GNU项目压缩工具 |
head | 显示指定文件内容的开头部分 |
help | 显示bash内建命令的帮助页面 |
killall | 根据进程名向运行中的进程发送一个系统信号 |
kwrite | 调用 KWrite文本编辑器 |
less | 查看文件内容的高级方法 |
link | 用别名创建一个指向文件的链接 |
ln | 创建针对指定文件的符号链接或硬链接 |
ls | 列出目录内容 |
makewhatis | 创建能够使用手册页关键字进行搜索的whatis数据库 |
man | 显示指定命令或话题的手册页 |
mkdir | 在当前目录下创建指定目录 |
more | 列出指定文件的内容,在每屏数据后暂停下来 |
mount | 显示虚拟文件系统上挂载的设备或将磁盘设备挂载到虚拟文件系统上 |
mv | 重命令名或移动文件,文件夹 |
nano | 调用nano文本编辑器 |
nice | 在系统上使用不同优先级来运行命令 |
passwd | 修改某个系统用户的账户的密码 |
ps | 显示系统上运行中进程的信息 |
pwd | 显示当前目录 |
renice | 修改系统上运行的优先级 |
rm | 删除文件 |
rmdir | 删除指定目录 |
sed | 使用编辑的文本流编辑器 |
sleep | 在的一段时间内暂停bash shell操作 |
sort | 基于指定的顺序组织数据文件中的数据 |
stat | 显示指定文件的文件统计数据 |
sudo | 以root用户账户身价运行应用 |
tail | 显示指定文件内容的末尾内容 |
tar | 将数据和目录归档到 单个文件中 |
top | 显示活动进程以及其他重要的系统统计数据 |
touch | 新建一个空文件,或更新一个已有文件的时间戳 |
umount | 从虚拟文件系统上删除一个已挂载的磁盘设备 |
uptime | 显示系统已运行了多久 |
useradd | 新建一个系统用户账户 |
uaserdel | 删除已有的一个系统账户 |
usermod | 修改已有系统用户账户 |
vi | 调用vim文本编辑器 |
vmstat | 生成一个详尽的系统内存和CPU使用情况报告 |
whereis | 显示指定命令的相关文件,包括二进制文件,源代码文件以及手册页 |
which | 查找可执行文件的位置 |
who | 显示当前系统中的登录用户 |
whoami | 显示当前用户的用户名 |
xargs | 从STDIN中获取数据项,构建并执行命令 |
zip | Windows下的PKZIP程序的Unix版本 |
A.3 环境变量
变量 | 描述 |
---|---|
* | 含有所有命令行参数(以单个文本值的形式) |
@ | 含有所有命令行参数(以多个文本值的形式) |
# | 命令行参数数目 |
? | 最近使用的前台退出状态码 |
- | 当前命令行选项标记 |
$ | 当前shell的进程ID |
! | 最近执行后台PID |
0 | 命令行中使用的命令名称 |
_ | shell的绝对路径名 |
BASH | 用户调用shell的完整文件名 |
BASHOPTS | 允许冒号分隔列表形式的shell选项 |
BASHPID | 当前bash shell的进程ID |
BASH_ALIASED | 含有当前所用别名的数组 |
BASH_ARGC | 当前子函数中的参数数量 |
BASH_ARGV | 含有所有指定命令行参数的数组 |
BASH_CMDS | 含有命令的内部的数组 |
BASH_COMMAND | 当前正在被执行的命令名 |
BASH_ENV | 如果设置了的话,每个bash脚本都会尝试在运行前执行由该 变量定义的起始文件 |
BASH_EXECUTION_STRING | 在-c命令行选项中用到的命令 |
BASH_LINENO | 含有脚本 中每个命令的行号的数组 |
BASH_REMATCH | 含有与指定的正则表达式匹配的文本元素的数组 |
BASH_SOURCE | 含有shell中已声明函数所在源文件名的数组 |
BASH_SUBSHELL | 当前shell生成的子shell数目 |
BASH_VERSINFO | 含有当前bash shell实例的主版本号和次版本号的数组 |
BASH_VERSION | 当前bash shell实例的版本号 |
BASH_STRACFED | 当设置一个有效的文件描述衔整数时,跟踪输出生成,并与诊断和错误信息分离开文件描述 符必须设置-x启动 |
COLUMNS | 含有当前bash shell实例使用的终端的宽度 |
COMP_CWORD | 含有变量COMP_WORDS的索引值,COMP_WORD包含当前光标所在的位置 |
COMP_KEY | 调用补全功能的按键 |
COMP_LINE | 当前命令行 |
COMP_POINT | 当前光标位置相对于当前命令起始位置的索引 |
COMP_TYPE | 实例类型所对应的整数值 |
COMP_WORDBREAKS | 在进行单词补全时用作单词分隔符的一组字符 |
COMP_WORDS | 含有当前命令行上所有单词的数组 |
COMPREPLY | 含有由shell函数生成的可能补全码的数组 |
COPROC | 含有用于匿名协程I/O的文件描述符的数组 |
DIRSTACK | 含有目录栈当前内容的数组 |
EMACS | 如果设置了该环境变量,则shell认为其使用的是emacs shell缓冲区,同时禁止行编辑功能 |
ENV | 当shell以POSIX模式调用时,每个bash脚本在运行之前都会执行由该环境变量所定义的起始文件 |
EUID | 当前用户的有效用户ID |
FCEDIT | fc命令使用的默认编辑器 |
FIGNORE | 以冒号分隔的后缀名列表,在文件名补全时会被忽略 |
FUNCNAME | 当前执行的shell函数的名称 |
FUNCNEST | 嵌套函数的最高层级 |
GLOBIGNORE | 以早号分隔的模式列表,定义了文件名展开时要忽略的文件名集合 |
GROUPS | 含有当前用户属组的数组 |
histchars | 控制历史记录展开的字符(最多可有3个) |
HISTCMD | 当前命令在历史记录中的编号 |
HISTCONTROL | 控制哪些命令留在历史记录列表中 |
HISTFILE | 保存shell历史记录列表的文件名(默认是.bash_history) |
HISTFILESIZE | 保存在历史文件中的最大行数 |
HISTIGNORE | 以冒号分隔的模式列表,用来决定哪些命令不存进历史文件 |
HISTSIZE | 最多在历史文件中保存多少条命令 |
HISTIMEFORMAT | 设置后,决定历史文件条目的时间戳的格式字符串 |
HOSTFILE | 含有shell在补全主机名时读取的文件的名称 |
HOSTNAME | 当前主机的名称 |
HOSTTYPE | 当前运行bash shell的机器 |
IGNOREEOF | shell在退出前必须收到连续的EOF字符的数量。如果这个值不存在,默认是1 |
INPUTRC | readline初始化文件名(默认是.inputrc) |
LANG | shell的语言环境分类 |
LC_ALL | 定义一个语言环境分类,它会覆盖LANG变量 |
LC_COLLATE | 设置对字符串值排定义了终端上可见的行数 |
名扩展和模式匹配时,如何解释其中的字符 | |
LC_MESSAGES | 决定解释前置美元符($)的双引号字符串的语言环境设置 |
LC_NUMERIC | 决定格式化数字时的所使用的语言环境设置 |
LINENO | 脚本中当前执行代码的行号 |
LINES | 定义了终端上可见的行数 |
MACHTYPE | 用“cpu公司系统”格式定义的系统类型 |
MAILCHECK | shell多久查看一次新邮件(以秒为单位,默认值是60) |
MAPFILE | 含有mapfile命令所读入文本的数组,当没有给出变量名的时候,使用该环境变量 |
OLDPWD | shell之前的工作目录 |
OPTERR | 设置为1时,bash shell会显示getopts命令产生的错误 |
OSTYPE | 定义了shell运行的操作系统 |
PIPESTATUS | 含有前台进程退出状态码的数组 |
POSIXLY_CORRECT | 如果设置了该环境变量,bash会以POSIX模式启动 |
PPID | bash shell父进程的PID |
PROMPT_COMMAND | 如果设置该环境变量,在显示命令行主提示符之前会执行这条命令 |
PS1 | 主命令行提示符字符串 |
PS2 | 次命令行提示符字符串 |
PS3 | select命令的提示符 |
PS4 | 如果使用了bash的-x选项,在命令行显示之前显示的提示符 |
PWD | 当前工作目录 |
RANDOM | 返回一个0~32 767的随机数,对其赋值可作为随机数生成器的种子 |
READLINE_LINE | 保存了readline行缓冲区中的内容 |
READLINE_POINT | 当前readline行缓冲区的插入点位置 |
REPLY | read命令的默认变量 |
SECONDS | 自shell启动到现在的秒数,对其赋值将会重置计时器 |
SHELL | shell的全路径名 |
SHELLOPTS | 已启用bash shell选项列表,由冒号分隔 |
SHLVL | 表明shell层级,每次启动一个新的bash shell时计数加1 |
TIMEFORMAT | 指定了shell显示的时间值的格式 |
TMOUT | select和read命令在没输入的情况下等待多久(以秒为单位)。默认值为零,表示无限长 |
TMPDIR | 如果设置成目录名,shell会将其作为临时文件目录 |
UID | 当前用户的真实用户ID(数字形式) |
可以用set内建命令来显示这些环境变量。对于不同的Linux发行版,开机时设置的默认shell变量经常会不一样。
更多推荐
所有评论(0)