《Linux命令行与Shell脚本编程大全(第3版)》读书笔记

第一章 初始Linux Shell

Linux可以划分为4个部分:

- Linux内核

- GNU工具

- 图形化桌面环境

- 应用软件

Linux系统的核心是内核。内核控制着计算机系统上的所有硬件和软件,在必要时分配硬件,并根据需要执行软件。

内核主要负责以下4种功能:

- 系统内存管理

- 软件程序管理

- 硬件设备管理

- 文件系统管理

操作系统内核的主要功能之一就是内存管理。内核不仅管理服务器上的可用物理内存,还可以创建和管理虚拟内存(即实际并不存在的内存)。

内核通过硬盘上的存储空间来实现虚拟内存,这块区域称为交换空间(swap space)。内核不断的在交换空间和实际的物理内存之间反复交换虚拟内存中的内容,这使得系统以为它拥有比物理内存更多的可用内存。

内存存储单元按组划分成很多块,这些块称作页面(page)。内核将每个内存页面放在物理内存或者交换空间。然后,内核会维护一个内存页面表,指明哪些页面位于物理内存内,哪些页面被换到了磁盘上。

内核会记录哪些内存页面正在使用中,并自动把一段时间没有访问的内存页面复制到交换空间区域(称为换出,swapping out),即使还有可用内存。当程序要访问一个已被换出的内存页面时,内核必须从物理内存换出另一个内存页面给它让出空间,然后从交换空间换入请求的内存页面。显然,这个过程要花费时间,拖慢运行的过程。只要Linux系统在运行,为运行中的程序换出内存页面的过程就不会停。

Linux操作系统将运行中的程序称为进程。进程可以在前台运行,将输出显示在屏幕上,也可以在后台运行,隐藏到幕后。内核控制着Linux系统如何管理运行在系统上的所有进程。

init进程为内核创建的第一个进程,用以启动系统上的其它进程。当内核启动时,它会将init进程加载到内虚拟内存中。内核在启动任何其它进程时,都会在虚拟内存中给新进程分配一块专有区域来存储该进程用到的数据和代码。某些Linux系统使用/etc/inittab来管理系统开机时要自启动的进程。另外一些使用/etc/init.d目录,该目录下的脚本自动启动或者停止,这些脚本通过/etc/rcX.d目录下的入口启动,这里的X代表运行级别。这些入口实际上是到/etc/init.d目录中启动脚本的符号链接。

Linux操作系统的init系统采用了运行级别。运行级决定了init进程运行/etc/inittab文件或/etc/rcX.d目录中定义好的某些特定类型的进程。

运行级为1时,只启动基本的系统进程和一个控制台终端进程。又称之为单用户模式。单用户模式通常用来在系统有问题时进行紧急的文件系统维护。在这种模式下,仅有一个人能登录到系统上操作数据。

标准的启动运行级是3,在这个运行级上,大多数应用软件都会启动。

运行级5支持启动图形化的X Window系统 。

任何Linux系统需要与之通信的设备,都需要在内核代码中加入其驱动程序代码。驱动程序代码相当于应用程序和硬件设备的中间人,允许内核与设备之间交换数据。在Linux内核中有两种方法用于插入设备驱动代码:

- 编译进内核的设备驱动代码

- 可插入内核的设备驱动模块

第一种方法已淘汰,第二种方法允许驱动代码插入到运行中的内核而无需编译内核。同时,当设备不再使用也可以将内核模块从内核中移走。

Linux系统将硬件设备当成特殊的文件,称为设备文件,分成3种:

- 字符型设备文件

- 块设备文件

- 网络设备文件

字符型设备文件是指处理数据时每次只能处理一个字符的设备。大多数类型的调制解调器和终端都是作为字符型设备文件创建的。块设备文件是指处理数据时每次能处理大块数据的设备,比如硬盘。网络设备文件是指采用数据包发送和接受的设备,包括各种网卡和一个特殊的回环设备。这个回环设备允许Linux系统使用常见的网络编程协议同自身通信。

Linux为系统上的每个设备都创建一种称为节点的特殊文件。与设备的所有通信都通过设备节点完成。每个节点都有唯一的数值对供Linux内核标识它。数值对包括一个主设备号和一个次设备号。类似的设备被划分到同一个主设备号下,次设备号用于标识主设备组下的某个特定设备。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。

Linux内核采用虚拟文件系统(Virtual File System,VFS)作为和每个文件系统交互的接口。这为Linux内同任何类型文件系统通信提供了一个标准接口。当每个文件系统被挂载和使用时,VFS将信息都缓存在内核中 。

供Linux系统使用的这组核心工具称为coreutils(core utilities)软件包,包含:

- 用以处理文件的工具

- 用以操作文本的工具

- 用以管理进程的工具

将多个shell命令放入文件作为程序执行,这些文件被称为shell脚本。所有Linux默认发行版都是Bash Shell。

X Window最流行的软件包是X.org。此外还有Fedora的Wayland还有Ubuntu开发出了Mir显示服务器。

除了X Window,还有GNOME桌面和KDE桌面,Unity桌面。

完整的Linux系统包称为发行版。发行版有3种:

- 完整的核心Linux发行版

- 特定用途的发行版

- LiveCD测试发行版

 

第二章 走进Shell

tty代表电传打字机(teletypewriter),指的是一台用于发送消息的机器。

 

第三章 基本的Bash Shell命令

/etc/passwd文件中第7列的内容表示某用户的启动Shell,如下:

nagios:x:501:501::/home/nagios:/bin/bash

最后1列(第7列)是/bin/bash,表示nagios用户登录后,默认使用bash shellLinux系统进行交互访问。

普通用户的Shell默认提示符号是美元符号($),而root用户的Shell默认提示符号是(#)。

man命令用来访问存储在Linux系统上的手册页面。比如想查找xterm的手册页面,可以输入:

[ec2-user@ip-172-31-16-143 ~]$ man xterm

读完手册页面,可以使用q退出。

如果不记得命令名,可以使用关键字,搜索手册页:

[ec2-user@ip-172-31-16-143 ~]$ man -k install

blib (3pm)           - Use MakeMaker's uninstalled version of a package

Bundle::DBI (3pm)    - A bundle to install DBI and required modules.

Bundle::PlRPC (3pm)  - A bundle to install PlRPC-Server, Client and prerequisites.

debuginfo-install (1) - install debuginfo packages and their dependencies

find-repos-of-install (1) - report which Yum repository a package was installed from

grub-install (8)     - install GRUB on your drive

这里使用man -k <关键字>,用于搜素相关的手册页。

Linux手册页的内容区域:

区域号

所涵盖的内容

1

可执行程序或者Shell命令

2

系统调用

3

库调用

4

特殊文件

5

文件格式与约定

6

游戏

7

概览、约定和杂项

8

超级用户和系统管理员命令

9

内核例程

如果需要查看某个命令对应的区域,可以这么做:

[ec2-user@ip-172-31-16-143 ~]$ man 1 hostname

这里就是查看hostname命令的区域1

除了man的方式,还有info页面方式,-help--help等方式来查看帮助。

Linux在路径名中不使用驱动盘符。Linux将文件存储在单个目录结构中,这个目录被称为虚拟目录(virtual directory)。虚拟目录将安装在PC上的所有存储设备的文件路径纳入单个目录结构中。Linux虚拟目录只包含一个称为根(root)目录的基础目录。Linux目录如下:

/home/Rich/Documents/test.doc

Linux PC上安装的第一块硬盘叫做根驱动器。根驱动器包含了虚拟目录的核心,其它目录都是从那里开始构建的。

Linux会在根驱动器上创建一些特别的目录,称之为挂载点。(mount point)挂载点事虚拟目录中用于分配额外存储设备的目录。虚拟目录会让文件和目录出现在这些挂载点目录中,然而实际上它们却存储在另外一个驱动器中。

常见Linux目录名称:

目录

用途

/

虚拟目录的根目录,通常不会在这里存储文件

/bin

二进制目录,存放许多用户级的GNU工具

/boot

启动目录,存放启动文件

/dev

设备目录,Linux在这里创建设备节点

/etc

系统配置文件目录

/home

主目录,Linux在这里创建用户目录

/lib

库目录,存放系统和应用程序的库文件

/media

媒体目录,可移动媒体设备的常用挂载点

/mnt

挂载目录,另一个可移动媒体设备的常用挂载点

/opt

可选目录,常用于存放第三方软件包和数据文件

/proc

进程目录,存放现有硬件和当前进程的相关信息

/root

root用户主目录

/sbin

系统二进制目录,存放许多GND管理员级工具

/run

运行目录,存放系统运作时的运行时数据

/srv

服务目录,存放本地服务的相关文件

/sys

系统目录,存放系统硬件信息的相关文件

/tmp

临时目录,可以在该目录中创建和删除临时工作文件

/usr

用户二进制目录,大量用户级别的GNU工具和数据文件都存储在这里

/var

可变目录,用以存放经常变化的文件,比如日志文件

常见的目录名字均基于文件系统层级标准(filesystem hierarchy standardFHS),很多Linux发行版都遵循FHS

使用cd命令进行目录切换。

使用pwd命令显示当前目录。

ls -F命令可以轻松的区分文件和目录:

[ec2-user@ip-172-31-16-143 ~]$ ls -F

aws_config.tar.gz          nagios/           plugins/                    stage_2016_04_27_06_20.tgz

full_package_download.py*  nrpe-install.sh*  stage_2016_04_27_06_10.tgz  start.sh*

GC.log                     nsca              stage_2016_04_27_06_19.tgz

ls -a可以显示隐藏文件:

[ec2-user@ip-172-31-16-143 ~]$ ls -a

.                  .bash_history             GC.log           plugins                     stage_2016_04_27_06_20.tgz

..                 .bash_logout              .lesshst         .rediscli_history           start.sh

.ansible           .bash_profile             nagios           .ssh                        .vim

.aws               .bashrc                   nrpe-install.sh  stage_2016_04_27_06_10.tgz  .viminfo

aws_config.tar.gz  full_package_download.py  nsca             stage_2016_04_27_06_19.tgz

ls -R可以递归列出目录中的文件:

[ec2-user@ip-172-31-16-143 ~]$ ls -R

.:

aws_config.tar.gz         GC.log  nrpe-install.sh  plugins                     stage_2016_04_27_06_19.tgz  start.sh

full_package_download.py  nagios  nsca             stage_2016_04_27_06_10.tgz  stage_2016_04_27_06_20.tgz

 

./nagios:

bin  etc  include  libexec  share  var

ls -F -R = ls -FR

ls -l显示长列表:

[ec2-user@ip-172-31-16-143 ~]$ ls -l

total 44

-rw-rw-r-- 1 ec2-user ec2-user  318 Mar 16  2016 aws_config.tar.gz

-rwxr-xr-x 1 ec2-user ec2-user 3995 Apr 27  2016 full_package_download.py

-rw-r--r-- 1 root     root      573 Mar 10  2016 GC.log

drwxr-xr-x 8 nagios   nagios   4096 May  6  2016 nagios

文件类型 | 文件权限 | 文件的硬链接总数 | 文件属主的用户名 | 文件属组的组名 | 文件大小(字节) | 文件的上次修改时间 | 文件名或者目录名

通配符?代表一个字符,通配符*代表0个或者多个字符。

通配符正式的名称叫做元字符通配符,比如:

[ec2-user@ip-172-31-16-143 ~]$ ls -l sta[gr]*

-rw-r--r-- 1 ec2-user ec2-user  72 Apr 27  2016 stage_2016_04_27_06_10.tgz

-rw-rw-r-- 1 ec2-user ec2-user  72 Apr 27  2016 stage_2016_04_27_06_19.tgz

-rw-r--r-- 1 ec2-user ec2-user  72 Apr 27  2016 stage_2016_04_27_06_20.tgz

-rwxrwxr-x 1 ec2-user ec2-user 415 Apr 27  2016 start.sh

[gr]表示g or r

又如:

[ec2-user@ip-172-31-16-143 ~]$ ls [a-c]

a  b  c

[a-c]表示ac

又如:

[ec2-user@ip-172-31-16-143 ~]$ ls [!a]

b  c  d

[!a]表示排除a

touch,创建一个文件或者更新文件修改时间。

如果只想修改文件的访问时间,使用touch -a

配合ls --time=atime,显示文件的访问时间(默认显示上一次的访问时间)。

cp的一个习惯,复制的如果是目录,需要带上 "/",这表示是一个目录,如果不带上"/"表示的是一个文件,因此需要额外注意。

cp -R递归复制目录。

制表键自动补全。

虚拟的副本称为链接。链接是目录中指向文件真实位置的占位符。Linux中有两种不同类型的文件链接:

  • 符号链接

  • 硬链接

符号链接就是一个实实在在的文件,它指向存放在虚拟目录结构中某个地方的另一个文件。

ln -s data_file sl_data_file

这里是sl_data_file指向data_filesl_data_file是符号链接,data_file是源文件。一般来说,sl_data_file这个符号链接所包含的大小是很小的,仅仅只是一个指向的符号文件。这两个文件的内容并不相同,是两个完全不同的文件。它们的inode编号也是不同的。

硬链接会创建独立的虚拟文件,其中包含了原始文件的信息和位置。但是从根本上而言,它们其实是同一个文件。引用硬链接文件等同于引用源文件。

ln code_file hl_code_file

它们是同一个inode。只能对于同一个存储媒体的文件创建硬链接。在不同媒体之间创建链接只能是符号链接。不要对软连接再创建软连接,那样容易混乱。

mv移动或者重命名。mv后,inode和时间戳不变,因为mv只影响文件名或者位置。mv -i移动时提示。

rm删除文件或者目录。rm -f,强制删除。rm -r递归删除。

mkdir创建目录。-p创建不存在的多个子目录。

rmdir删除空目录。

可以先rm删除某目录下的所有文件,再rmdir删除空目录。(好习惯)

tree展示目录、子目录和其中的文件。

file查看文件类型。

cat查看文件,cat -n给行加上行号,cat -b只给有文本的行加上行号,cat -T使用^I代替制表符输出。

more分页工具,查看文件。

less查看文件,高级工具。

tail显示最后10行,tail -n <行数>显示倒数的行数,tail -f持续输出。

head显示前10行,head -n <行数>显示前多少行数。

 

第四章 更多的Bash Shell命令

PIDProcess ID,也就是进程的ID

ps命令支持3种不同类型的命令行参数:

  • Unix风格的参数,前面加单破折号;

  • BSD风格的参数,前面不加破折号;

  • GNU风格的参数,前面加双破折号;

Unix风格的ps命令参数:

-A,显示所有进程

-N,显示与指定参数不符的所有进程

-a,显示除控制进程和无终端进程外的所有进程

-d,显示除控制进程外的所有进程

-e,显示所有进程

-C cmdlist,显示包含在cmdlist列表中的进程

-G grplist,显示组IDgrplist列表中的进程

-U userlist,显示属主的用户IDuserlist列表中的进程

-g grplist,显示会话或组IDgrplist列表中的进程

-p pidlist,显示PIDpidlist列表中的进程

-s sesslist,显示会话IDsesslist列表中的进程

-t ttylist,显示终端IDttylist列表中的进程

-u userlist,显示有效用户IDuserlist列表中的进程

-F,显示更多额外输出(相对-f参数而言)

-O format,显示默认的输出列以及format列表指定的特定列

-M,显示进程的安全信息(SELinux

-c,显示进程的额外调度器信息

-f,显示完整格式的输出

-j,显示任务信息

-l,显示长列表

-o format,仅显示由format指定的列

-y,不要显示进程标记(process flag,表明进程状态的标记)

-Z,显示安全标签(security context)信息

-H,用层级格式来显示进程(树状,用来显示父进程)

-n namelist,定义了WCHAN列显示的值

-w,采用宽输出模式,不限宽度显示

-L,显示进程的线程

-V,显示ps命令的版本号

如果想查看系统上运行的所有进程,可用ps -ef参数组合。

ps -ef的输出值意义:

UID,启动这些进程的用户。

PID,进程的进程ID

PPID,父进程的进程号(如果该进程是由另一个进程启动的)。

C,进程生命周期中的CPU利用率。单位为%

STIME,进程启动时的系统时间。

TTY,进程启动时的终端设备。

TIME,运行进程需要的累计CPU时间。这里是实际花费CPU的时间,而不是系统时间。

CMD,启动的程序名称。

ps如果使用了-l参数之后,得到更多的信息:

F,内核分配给进程的系统标记。说明这个进程的权限。4表示此进程为root权限,1表示此子进程仅能fork

S:进程的状态(R代表正在运行,S休眠可被唤醒,D不可被唤醒,Z僵尸进程,T停止)

僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。

PRI,进程的优先级(数字越大表示优先级越低)

NI,谦让值用来参与决定优先级(数字越大表示优先级越低)

ADDR,进程的内存地址。如果是个running进程,一般显示"-"

SZ,假如进程被换出,所需要的交换空间的大致大小。也就是用了多少实际内存。

WCHAN,进程休眠的内核函数的地址。如果是个running进程,一般显示"-"

BSD风格参数:

ps aux为例子:

VSZVMSIZE,一个进程占用的总的地址空间大小,它包括了没有映射到内存中的页面。

RSS,"Resident Set Size", 实际驻留"在内存中"的内存数。不包括已经交换出去的代码。举一个例子:如果你有一个程序使用了100K内存,操作系统交换出40K内存,那么RSS为60K。RSS还包括了与其它进程共享的内存区域,这些区域通常用于libc库等。

SHARE,RSS中与其它进程共享的内存部分大小。

<,该进程运行在高优先级上。

N,该进程运行在低优先级上。

L,该进程有页面锁定在内存中。

s,该进程是控制进程。

l,该进程是多线程的。

+,该进程运行在前台。

命令top的指标:

PID,进程的ID

USER,进程属主的名字。

PR,进程的优先级。

NI,进程的谦让值。

VIRT,进程占用的虚拟内存总量。

RES,进程占用的物理内存总量。

SHR,进程和其它进程共享的内存总量。

S,进程状态,D可中断的休眠状态,R正在运行,S休眠,T停止,Z僵尸进程。

%CPU,进程使用的CPU时间比例。

%MEM,进程使用的内存占可用内存比例。

TIME+,自进程启动到目前为止的CPU时间总量。

COMMAND,程序名。

命令top默认是根据%CPU值排序的。

kill -9无条件杀死进程。

killall http*,杀死所有以http开头的进程。比如这样杀死Apache Web服务器的httpd服务。

mount命令输出当前系统上挂载的设备列表。

/dev/sda1 on /boot type ext3 (rw)

媒体的设备文件名 | 挂载点 | 文件系统类型 | 访问状态

手动挂载需要root权限。

mount -t type device directory

type

vfatWindows长文件系统。比如U盘。

ntfsWindows高级文件系统。

iso9660cd or dvd

mount命令参数:

-a,挂载/etc/fstab文件中指定的所有文件系统。

-f,模拟挂载。

-v,详细模式。

-l,给ext2ext3XFS文件系统自动添加文件系统标签。

-n,挂载设备,但不注册到/etc/mtab中。

-r,挂载设备只读。

-w,挂载设备可写。

-L label,按指定label挂载。

-U uuid,按指定uuid挂载。

-o,添加选项,ro只读,rw读写,user允许普通用户挂载文件系统,check=none挂载文件系统时不进行完整性校检,loop挂载一个文件。

Linux不能直接弹出已挂载的CD,需要先卸载,才能弹出。

umount [ directory | device ],卸载设备。卸载遇到有问题时,可使用lsof查看哪个程序在访问这个设备,然后杀死,才能卸载。

df显示每个数据的已挂载文件系统。一般df -h。如果某个文件已被删除,但是并没有真正释放,这个值是不会被算进空闲空间的。

du显示某个特定目录的磁盘使用状态。一般du -sh

sort排序。默认使用字符排序,-n使用数字排序,-M按三字符月份排序,-r降序排序,-t指定分隔符,-k指定排序的字段。

grep [options] pattern [file]

grep命令会在输入或指定的文件中查找包含匹配指定模式的字符的行。-v反向搜索,-n显示匹配行号,-c匹配多少行,-e指定多个匹配(-e t -e f),grep支持正则表达式。

Linux文件压缩工具:

bzip2.bz扩展名。

gzip.gz扩展名。

zip.zip扩展名。

gzip软件用来压缩文件。gzcat用来查看压缩过的文本文件的内容。gunzip用来解压文件。

tar命令归档:

-c,创建一个tar归档文件。

-v,处理时显示文件。

-f,输出到文件。

-jbzip2格式。

-zgzip格式。

-p,保留权限。

-x,提取文件。

-C dir,切换到目录。

-t,列出内容。

tar -tf test.tar,列出tar文件中的内容,但是不提取。

比如.tgz文件,是gzip压缩过的tar文件。可以使用tar -xvzf解压缩

 

第五章 理解Shell

/bin/bash/bin/sh不是一回事:

sh跟bash的区别,实际上就是bash有没有开启posix模式的区别,在posix模式中,某些命令如let不能用,/bin/bash --posix就是等于/bin/sh。一般/bin/sh作为软链接,指向/bin/bash的。

用于登录某个虚拟控制器或者在GUI中运行终端仿真器时所启动的默认的交互shell,是一个父shell。由父shell创建的shell,叫子shell

进程列表写法(command grouping)写法是一种子进程的启动方法,比如:

(pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls)

要知道是否跑的是子进程,可以echo $BASH_SUBSHELL,如果返回值是0,则表示没有跑子进程,如果返回值1或者更大的数字,则是跑了子进程。一般使用子shell进行多进程处理。不过采用子shell成本不菲,但是会明显拖慢处理速度。但这也不是真正意义上的多进程处理,因为终端控制着子shellI/O

Sleep 3000&,放在后台跑,睡眠3000秒。可使用jobs -l查看后台命令。

coproc my_job { sleep 10; sleep 2 }

coproc就是利用子shell,在后台跑东西。就等于( sleep 10 ; sleep 2 )&

外部命令有时候也被称为文件系统命令,是存在于Bash Shell之外的程序,它们并不是shell程序的一部分。外部命令通常位于/bin/usr/bin/sbin/usr/sbin中。

ps就是一个外部命令,可以使用whichtype找到它。

当外部命令执行时,会创建出一个子进程,这个叫衍生(forking)。比如ps执行后,它的父进程就是bash,它是被fork出来的子进程。当进程执行衍生操作时,需要花费时间和经理来设置新的子进程的环境,所以说,外部命令多少还是有些代价的。

内建命令和外部命令相比,不需要子进程来执行。它和Shell编程成了一体,作为shell工具的部分存在,不需要借助外部程序文件来运行。

有些命令有多种实现,比如echopwd有内建命令也有外部程序。

内建命令history,查看历史操作命令。变量HISTSIZE决定了history显示多少条历史记录。

!!命令表示使用上一条命令。

命令历史记录被保存在家目录下的.bash_history文件中。bash命令的历史记录是先放在内存中,当shell退出后才被写入历史文件中。如果需要强制写入,使用history -a。当你打开多个终端,.bash_history只有在打开首个终端时才会被读取,要强制读取历史命令可以使用history -n。如果新的终端需要使用第一个终端的历史命令记录,第一个终端使用history -a,新的终端使用history -n

alias命令是另一个shell内建命令,命令别名运行为常用的命令(和参数)创建另一个名称,从而输入量减少到最低。使用alias查看别名。alias li='ls -li',这个定义仅仅在当前shell有效,如果需要一直有效,需要写入.bash_rc或者.bash_profile文件。

 

第六章 使用Linux环境变量

Bash Shell用一个叫做环境变量的特性来存储有关shell会话和工作环境的信息。这项特性允许你在内存中存储数据,以便程序或shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。

环境变量分为:全局变量和局部变量。

全局变量对于shell会话和所有生成的子shell都是可见的。局部变量只是对于创建它们的shell可见。全局变量对那些所创建的子shell需要获取父shell信息的程序来说非常有用。系统环境变量一般都是全大写。使用env或者printenv显示全局变量。查看单个环境变量可以使用printenv

[root@centos7-python ~]# printenv HOME

/root

或者使用echo $HOME

set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量和用户定义变量。

一般自定义变量请使用小写,系统环境变量用大写,这样不容易混淆。

export var,这就是把var这个变量变成全局变量。子进程可以继承父进程的全局变量,但父进程不会继承子进程的环境变量,如果父进程中设置了var = 1,子进程var也就是1,当子进程把var = 2,此时父进程的var还是1,不会被继承。

unset用户删除环境变量,unset var,记得不要使用$

记得使用变量的值,请加上$。如果是只对变量进行操作,请不要加上$

如果对子进程删除了某个全局变量,父进程的全局变量不受影响。

Bash Shell环境变量:

HOME,当前用户的主目录。

IFSshell用来将文本字符串分割成字段的一系列字符。

MAIL,当前用户收件箱的路径(Bash Shell会检查这个文件,看看有没有新邮件)

OPTARGgetopts命令处理的最后一个选项参数值。

OPTINDgetopts命令处理的最后一个选项参数的索引号。

PATHshell查找命令的目录列表,由冒号分割。

PS1shell命令行界面的主提示符。

PS2shell命令行界面的次提示符。

BASH,当前shell实例的全路径名。

BASH_COMMANDshell正在执行的命令或者马上就执行的命令。

BASH_ENV,设置了的话,每个bash脚本会在运行前先尝试运行该变量定义的启动文件。

BASH_VERSION,当前运行的bash shell版本号。

BASH_PID,当前bash进程PID

EUID,当前用户的有效用户ID(数字形式)。

HISTFILE,保存shel历史记录列表的文件名(默认是.bash_history)。

HISTFILESIZE,历史文件最多存多少行。

HOSTNAME,主机名字。

HOSTTYPE,主机架构。

LANGshell语言环境类别。

LC_ALL,语言环境类别,能覆盖LANG

LINES,终端上可见行数。

MAILCHECKshell查看新邮件的频率(默认60秒)。

PPIDshell的父进程PID

PS3select命令提示符。

PS4,使用了bash -x的选项,输出的提示信息。

RANDOM,返回一个0~32767的随机数

TMOUT,没输入情况下等多久(秒)退出。

UID,真实用户ID

SECONDS,自动shell启动到现在的秒数(对其赋值可重置)。

如果需要给PATH变量加入新的路径,可以这么做:

[root@centos7-python ~]# echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

[root@centos7-python ~]# PATH = $PATH:/tmp

-bash: PATH: command not found

[root@centos7-python ~]# PATH=$PATH:/tmp

[root@centos7-python ~]# echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/tmp

如果是全局的变换,需要:

export $PATH

还有种办法,直接进入你需要的目录,然后把.直接加进来:

PATH=$PATH:.

在登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫做启动文件或环境文件。bash检查的启动文件取决于启动shell的方式。启动shell有三种方式:

  • 登录时作为默认登录shell

  • 作为非登录shell的交互式shell

  • 作为脚本运行的非交互式shell

当登录Linux系统时,shell会作为登录shell启动。登录shell会从5个不同的启动文件里读取命令:

  • /etc/profile

  • $HOME/.bash_profile

  • $HOME/.bashrc

  • $HOME/.bash_login

  • $HOME/.profile

其中/etc/profile是系统上磨人的shell主启动文件。系统上每个用户登录都会执行这个启动文件。

运行完/etc/profile -> /etc/profile.d目录下的脚本,然后开始运行$HOME/.bash_profile,在这个文件中,会去找$HOME/.bashrc,如果有则执行,没有则不执行。$HOME/.bashrc又去找/etc/bashrc,如果有执行,没有则不执行。/etc/bashrc里面也定义了很多变量。此外,不要忘了/etc/profile.d目录下面很多东西也会被执行(位于/etc/profile后执行)。登录shell是需要输入密码的。

如果你的shell不是登录时启动的(比如手动敲下bash时启动或者任何不需要输入密码的登录 ),如果是这种非登录shell,只检查$HOME/.bashrc,因此写一些用户自定义别名或者环境变量时,写$HOME/.bashrc

对于全局变量的设定一般放在/etc/profile中或者/etc/profile.d目录下创建shell脚本导入变量,第二种办法更好,因为一旦系统升级/etc/profile可能被覆盖。

环境变量可作为数组使用。数组是能够存储多个值得变量。这些值可以单独饮用,也可以拿整个数组引用。

[root@centos7-python ~]# mytest=(1 2 3 4 5)

[root@centos7-python ~]# echo ${mytest[2]}

3

索引从0开始。

如果要输出整个数组,则使用echo ${mytest[*]}

也可以改变数组的某个值:

mytest[2]=seven

删除数组中的某个值:

unset mytest[2]

这个索引2被删除后,查看数值是空,但是实际上索引的个数没变,只是这个索引对应的值没了。
删除整个数组:

unset mytest

 

第七章 理解Linux文件权限

用户权限是通过创建用户时分配的用户IDUID)来跟踪的,UID是数值,每个用户都有唯一的UID,但在系统登录时用的不是UID,而是登录名。登录名是用户用来登录系统的最长八个字符的字符串(可以是数字也可以是字母),同时会关联一个对应的密码。

Linux系统使用一个专门的文件来将用户的登录名匹配到对应的UID值。这个文件就是/etc/passwd文件,包含了一些与用户有关的信息。root用户账户是Linux系统管理员,固定分配UID0Linux系统会为了各种各样的功能创建不同的用户账户,而这些账户不是真正的用户。这些账户叫做系统账户,是系统上运行的各种服务进程访问资源用的特殊账户。所有运行在后台的服务都需要一个系统用户账户登录到Linux系统上。早期的服务都是用root账户登录,这样一旦某个服务被攻陷,黑客就得到了root权限,很不安全。现在每个服务使用自己的系统账号,及时服务被攻陷,黑客也只能拿到系统账号,但是无法访问整个系统。

Linux系统账户预留了500以下的UID值(0root1~499为系统账户)。有些服务甚至需要使用特定的UID才能正常工作。普通用户被创建时,都是从UID 500开始的。(并非所有Linux发行版都这样)

/etc/passwd的列说明:

登录用户名 | 用户密码 | 用户账户UID(数字)| 用户账户的组ID(数字)| 用户账户的文本描述(备注字段)| 用户HOME目录的位置 | 用户的默认Shell

/etc/passwd中的密码都设置为了x,这表示密码被隐藏了。密码实际上被隐藏到了/etc/shadow中,只有特定的程序(比如登录程序)才能访问这个文件。

不建议直接修改/etc/passwd文件。

/etc/shadow文件对Linux系统密码管理提供了更多的控制。只有root用户才能访问它,比起/etc/passwd安全多了。

/etc/shadow9个字段,分别是:

/etc/passwd对应的登录名 | 加密后的密码 | 上次修改密码的日期(1970.1.1表示1,1971.1.1表示366,如此计算) | 密码经过多少天后才能更改(0表示随时可以改)多少天后必须更改密码(如果设定了99999,就基本等于一直不要改了)| 密码过期前多少天提醒用户更改密码 | 密码过期后多少天禁用用户账户 | 账号失效日期(1970.1.1表示1,1971.1.1表示366,如此计算) | 保留字段

创建用户的命令是useradd,这个命令根据一个文件/etc/default/useradd文件来预设这个新建用户的一些初始值。如果想查看useradd的一些预设值,可以使用useradd -D。如果创建一个新用户,默认会做以下操作(根据/etc/default/useradd文件):

  • 新用户会被添加到GID100的公共组。

  • 新用户的HOME目录将会位于/home/<loginname>

  • 新用户账户密码在过期后不会被禁用。

  • 新用户账户没有被设置过期日期。

  • 新用户账户将bash shell作为默认shell

  • 系统会将/etc/skel目录下的内容复制到用户HOME目录下。

  • 系统为该账户在mail目录下创建一个勇于接收邮件的文件。

useradd的一些选项参数:

-c comment,给新用户添加注释。

-d home_dir,为主目录指定一个名字(如果不想用登录名作为目录名的话)。

-e expire_date,用YYYY-MM-DD格式制定一个账户过期日期。

-f inactive_days,指定这个账户密码过期多少天后这个账户被禁用,0表示一过期就禁用,-1表示禁用这个功能。

-g initial_group,指定用户登录组的GID或者别名。

-G group,一个或者多个附加组。

-k,必须和-m一起用,把/etc/skel目录的内容复制到用户HOME目录。

-m,创建用户HOME目录。

-M,不创建用户HOME目录。

-n,创建一个与用户名同名的新组。

-r,创建系统账户。

-p passwd,为用户指定默认密码。(/etc/shadow明文)

-s shell,指定默认的登录shell

-u uid,指定唯一UID

修改useradd默认参数(配合-D):

-b default_home,创建默认HOME位置。

-e expiration_date,更改过期事件。

-f inactive,过期后多少天账户被禁用。

-g group,默认组名或GID

-s shell,默认Shell

比如:

useradd -D -s /bin/tsch

userdel用于删除用户,默认情况下只会删除/etc/passwd中的用户信息,这个用户的其它任何文件不会被删除。

如果userdel -r,则会删除HOME目录和邮件目录。

用户账户修改工具:

usermod,修改用户账户字段,还可以指定主要组和福家族所属关系。

passwd,修改已有用户的密码

chpasswd,从文件中读取登录密码对,并更新密码。比如:chpasswd < userpasswd.txt,在这个文件中的格式为,用户名:密码,比如test:123456,这种方式输入给chpasswd,这样可以批量修改用户的密码。

chage,修改密码的过期日期。

chfn,修改用户的备注信息。

chsh,修改用户的默认登录shell

usermod参数:

-c comment,修改备注字段。

-e expiration_date,修改过期日期。

-g group,修改默认登录组。

-l username,修改用户账户的登录名。

-L username,锁定账户。

-p passwd,修改账户密码。(/etc/shadow明文)

-U username,解除锁定。

passwd -e <username>,这个username下次登录时需要自己修改密码。(强制)

chsh -s /bin/csh test,给test用户指定csh这个shell,注意路径需要写全。

chage几个参数:

-d,设置上次修改密码到现在的天数。

-E,设置密码过期的日期。

-I,设置密码过期到锁定账户的天数。

-m,设置密码修改之间最少需要多少天。

-W,设置密码过期前多少天提醒。

日期值可以是YYYY-MM-DD或者1970.1.1到那天的数值。

每个Linux组也有一个GID。组的信息保存在/etc/group文件中。有4个字段:

组名 | 组密码 | GID | 属于该组的用户列表

组密码允许非组内成员通过它临时称为该组成员。

不建议对/etc/group文件进行修改。

/etc/passwd中的某个用户以某个组作为默认组时,用户账户不会作为该组成员再出现在/etc/group中。

groupadd创建新组。

groupmod -g,修改GIDgroupmod -n,修改组名。

umask用来设置所创建文件和目录的默认权限,一共4位数。第一位是安全项,叫做粘着位(sticky bit),后面3位是文件或者目录对应的8进制值。umask值实际上就是个掩码,屏蔽掉一些不想授予安全级别的权限。比如文件的全权限值为666,目录的全权限值是777,这样通过umask的处理(默认0022),也就是全权限值减去umask值(022),得到实际的权限,文件也就是644,目录就是755,这也就是新建的文件或者目录的默认权限。一般umask值会设置在/etc/profile中,也有一些设置在/etc/login.defs中(Ubuntu),可以利用umask来设定新的值,比如:umask 026

chmodchown

chown options owner[.group] file

chown dan newfile

chown dan.shared newfile

chown .rich newfile

chown test. Newfile <- 如果用户名和组名匹配,则这里就是test用户和test组。

chgrp

SUID:当文件被用户使用时,程序会以文件属主的权限运行。权限4

SGID:对文件来说,程序会以文件属组的权限运行;对目录来说,目录中创建的新文件会以目录默认的属组作为默认属组。SGID对文件共享非常重要,启用SGID后,可以强制在一个共享目录下创建的新文件都属于该目录的属组,这个组也就成为了每个用户的属组。权限2

粘着位:

对一个文件设置了sticky-bit之后,尽管其他用户有写权限, 也必须由属主执行删除、移动等操作。对一个目录设置了sticky-bit之后,存放在该目录的文件仅准许其属主执行删除、 移动等操作。权限1

 

第八章 管理文件系统

Linux操作系统中引入的最早的文件系统叫做扩展文件系统(extended filesyste,也就是ext),这样可以使用虚拟目录来操作硬件设备,在物理设备上按照定长的块来存储设备。ext文件系统采用索引节点的系统来存放虚拟目录中所存储文件的信息。索引节点系统在每个物理设备中创建一个单独的表(称为索引节点表)来存储这些文件的信息。存储在虚拟目录中的每一个文件在索引节点表中都有一个条目。ext文件系统名称中的extended部分来自其跟踪的每个文件的额外数据,包括:

  • 文件名

  • 文件大小

  • 文件的属主

  • 文件的属组

  • 文件的权限

  • 指向存有文件数据的每个硬盘块的指针

Linux通过唯一的数值(索引节点号)来引用索引节点表中的每个索引节点,这个值是创建文件时由文件系统分配的。文件系统通过索引节点号而不是文件全名和路径来标识的。

存储数据用的块分散在整个设备中,这称为碎片化。(fragmentation)数据块的碎片化会降低文件系统的性能,因为需要长时间在设备中查找特定文件的所有块。

日志文件系统的工作方式是先把文件的更改临时写入临时文件(又叫日志,journal),等数据成功写入存储设备和索引节点表后,再删除对应的日志条目。有3种日志方法:

数据模式,索引节点和文件都会被写入日志,丢失数据风险低,但是性能差。

有序模式,只有索引节点被写入日志,但是只有数据被成功写入后才会删除。在性能和安全上取得折中。

回写模式,只有索引节点被写入日志,但不控制文件数据何时写入,丢失风险高,但是依然比不使用日志系统好。

ext42008年受到Linux内核官方支持,支持压缩和加密,还支持区段(extent)特性。区段在存储设备上按照块分配空间,但在索引节点表中只保存起始块的位置。由于无需列出所有用来存储文件中数据的数据块,它可以在索引节点表中节省一些空间。

ext4还引入了块预分配技术(block preallocation),如果想在存储设备上给一个知道有变大的文件预留空间,ext4文件系统可以为文件分配所有需要用到的块,而不仅仅是那些现在已经要用到的块。ext4文件系统用0填满预留的数据块,不会将它们分配给其它文件。

ResierFS只支持回写日志模式,也就是只把索引节点表数据写到日志文件。它是最快的日志文件系统之一。它有2个特性,1可以在线调整已有文件系统的大小,2是尾部压缩技术(tailpacking),也就是能将文件的数据填进另一个文件数据块的空白空间。

JFS采用的是有序日志方法。由IBM开发,目前是JFS2(在Linux中依然称为JFS)。

XFS类似于ResierFS,也是回写日志模式,能调整文件系统大小,但是只能扩大不能缩小。

日志文件系统的另一种选择是写时复制(copy-on-writeCOW)技术。COW利用块照兼顾了安全性和性能,如果要修改数据,会使用克隆或者可写块照。修改过的数据不会直接覆盖当前数据,是被放入文件系统中的另一个位置。即便是数据修改已经完成,之前的旧数据也不会被重写。目前COW技术主要用在BtrfZFS上。

ZFSSolaris的文件系统,是Sun公司开发的,目前由于没有GPL,还没有使用到Linux上。OpenZFS项目正在进行中,有望改善这一情况。

Btrf文件系统,也称为B树文件系统。是Oracle公司开发的。是在Reiser4上增加了可靠性。OpenSuse使用Btrf作为默认的文件系统。

fdisk工具用来帮助管理安装在系统上的任何存储设备上的分区。必须拥有超级管理员权限。

fsck用于恢复文件系统。fsck使用/etc/fstab文件来自动决定正常挂在到系统上的存储设备的文件系统。如果存储设备尚未挂载(比如刚刚在新的设备上创建了个文件系统),需要用-t命令行选项来指定文件系统类型。fsck只能在没有挂载的文件系统上运行,对于大多数文件系统,可以先卸载再检查最后挂载的方式恢复文件系统。对于根文件,可采用LiveCD方式,然后对根进行恢复。

逻辑卷管理(logical volume managerLVM)的核心在于如何处理安装在系统上的硬盘分区。在逻辑卷的管理世界中,硬盘称为物理卷(physical volumePV),多个卷集中在一起形成卷组(volume groupVG)。逻辑卷管理把卷组视为一个物理硬盘。卷组之后提供一个物理平台创建逻辑分区,而这些逻辑分区则包含了文件系统。VG中的逻辑分区就是逻辑卷(logical volumeLV)。基本架构就是:

逻辑卷1

逻辑卷2

卷组

物理卷1

物理卷2

分区1

分区2

硬盘1

也就是1块硬盘被分为2个分区,分区1LVM中就是物理卷1,分区2LVM中就是物理卷2,物理卷1+2(或者加更多的物理卷)组成了卷组,然后在这个卷组上创建任意多个LV

目前是LVM2,有如下功能:

  • 块照:LVM允许在逻辑卷在线的状态下将其复制到另一个设备。传统备份时,文件复制到备份媒体上需要将文件锁定。

  • 条带化(striping):也就是跨多个物理卷创建逻辑卷。这有助于提高硬盘性能,因为Linux可以把一个文件写入多个数据块同时写入多个硬盘。但是一个硬盘就是读写磁头到不同位置。读数据时,LVM可以从多个硬盘读数据,也可以加快速度。

  • 镜像:LVM镜像是一个实时更新的逻辑卷的完整副本。一旦镜像创建完成,LVM会为文件系统的每次写操作执行两次,一次是主逻辑卷,一次是镜像副本。但是这样会降低写入性能,但是安全。

LVM的软件包叫lvm2。创建LVM时需要在分区中选择8e分区类型。然后pvcreate穿件物理卷,比如:pvcreate /dev/sdb1。查看物理卷信息,pvdisplay /dev/sdb1

创建卷组:

vgcreate vol1 /dev/sdb1

查看卷组信息:

vgdisplay vol1

创建卷组:

lvcreate -n lv1 vol1

-n表示起一个名字。

-L给大小。

-l给区段。(块)

查看卷组信息:

Lvdisplay lv1

最后别忘了创建文件系统,mkfs.xx

修改LVM命令:

vgchange,激活和禁用卷组。

vgremove,删除卷组。

vgextend,将物理卷增加到卷组中。

vgreduce,从卷组中删除物理卷。

lvextend,增加逻辑卷大小。

lvreduce,减小逻辑卷大小。

注意逻辑卷增加或者减少后,需要手动处理文件系统。

 

第九章 安装软件程序

包管理系统,package management systemPMSPMS利用一个数据库来记录各种相关内容:

  • Linux系统上已经安装了什么软件包。

  • 每个包安装了什么文件。

  • 每个已安装的软件包的版本。

软件包存储在服务器上,这些服务器称为仓库。(repository

PMS可以检测到包与包之间的依赖关系。PMS不过还没有统一,PMS基础工具是dpkgrpm

基于Debian发行版的(如UbuntuLinux Mint)使用的是dpkg命令,dpkg会和Linux系统上的PMS交互,用来安装、管理和删除软件。

基于Red Hat的发行版本(如FedoraopenSUSEMandriva)使用的是rpm命令。

注意了,dpkgrpm不是PMS全部,只是它的核心。

dpkg基于DebianPMS工具核心,PMS工具有:

  • apt-get

  • apt-cache

  • aptitude

到目前为止,最常用的是aptitude

aptitude有个交互式界面,直接输入就可以看到。

查看某个包的详细信息:

aptitude show mysql-client

查看某个包的安装文件:

dpkg -L vim-common

查看特定文件属于哪个包:

dpkg --search absolute_file_name

查找含有关键字的软件包:

aptitude search wine

输出i,表示已装好了。

pv,表示可用但没装。

安装软件包:

aptitude install wine

自动更新所有软件包:

aptitude safe-upgrade

升级Debian系统:

aptitude dist-upgrade

aptitude full-upgrade

只删除包,不删除数据和配置文件:

aptitude remove wine

删除软件和数据和配置文件:

aptitude purge wine

接着看看删干净了没:

aptitude search wine

c,表示已删除包,但是配置文件没有被删除。

p,说明包删除,配置文件也删除了。

aptitude的默认仓库在/etc/apt/sources.list中。安装仓库中的包最安全,因为它很好地解决了依赖性问题。

仓库文件格式:

deb(or deb-src) address distribuction_name package_type_list

实际例子:

deb http://extras.ubuntun.com/ubuntutrusty main

deb-src http://extras.ubuntu.com/ubuntutrusty main

deb表示一个已经编译的程序源,deb-src表示是一个源代码的源。

address是软件仓库的web地址。

distribution_name是仓库的发行版本的名称。

package_type_listmainrestricteduniversepartner

yum用于RHELCentOSFedora

urpm用于Mandriva

zypper用于openSUSE

yum list installed,列出系统上已安装的包。

yum list xterm,列出个别软件的详细信息。

yum provides file_name,某个特定文件属于哪个包。

yum whatprovides command_name,查看某个命令属于哪个包。

yum install package_name,在线安装某个包。

yum localinstall package_name,本地安装某个包。

yum list updates,列出所有已安装包的可用更新。

yum update package_name,升级某个包。

yum update,所有包更新。

yum remove package_name,删除包但是保留配置。

yum erase package_name,删除包和配置文件。

有时候安装多个软件包,某个包的依赖关系可能会被另一个包的安装覆盖掉,这叫做损坏的包依赖关系(broken dependency)。

要解决这个问题,首先:

Yum clean all

然后 yum update,如果还是不行,那么:

Yum deplist package_name

上面的命令显示了xterm包的依赖关系和什么软件可以提供这些库的依赖关系。如果还是不行,可以使用

Yum update --skip-broken

就是允许你忽略哪个依赖关系损坏的包,继续去更新其它包。

请尽可能使用通过审核的仓库。

Yum repolist,可以知道正在使用哪些仓库。yum的仓库在/etc/yum.repos.d/目录下。

有些仓库网站会提供一个rpm文件给我们,下载下来,yum localinstall之后,所有仓库设置完毕!

sysstat软件包提供了各种检测工具。
源码安装通用三步骤:

./configure

Make

Make install

 

第十章 使用编辑器

主要有vimnanoemacsKWriteKateGNOME

有些发行版本没有预装vim,需要手动安装。

vim技巧:

PageDown(或者ctrl + F):下翻一屏。

PageUp(或者ctrl + B):上翻一屏。

G:移动到最后一行。

gg:移动到第一行。

Num G:移动到第num行。

x:删除当前光标位置字符。

dd:删除光标行。

dw:删除光标位置单词。

d$:删除光标位置到行尾。

J:删除光标位置行尾的换行符(拼接行)

u:撤销一次编辑。

R:替换模式。

比如2x,则是删除两次的x5dd就是执行5dd

d就是删除的意思,如果换成y就是复制,后面是一样的,比如yd就是复制光标当前行,又如y$复制光标当前位置到行尾等。

v:进入可视模式。高亮复制区域。

替换:

:s/old/new,仅替换一次,并且是第一个匹配。

:s/old/new/g,替换一行所有。

:n,ms/old/new/g,在nm之间替换。

:%s/old/new,替换所有行的第一个匹配。

:%s/old/new/g,替换这个文件中的oldnew

:%s/old/new/gc,替换这个文件中的oldnew,但是提示。 

 

第十一章 构建基本脚本

使用多个命令:

date ; who

使用分号分隔开。命令行字符数不能超过255

Shell脚本的第一行格式:#!/bin/bash

使用注释:#

默认情况下,自己写shell脚本可以继承这个用户的环境变量,比如在脚本中echo $HOME,这个HOME变量在脚本中并没有定义,但是确实是可以调用的,因为HOME变量已经被继承了。

如果想要转义,可以使用\。一般变量写法最好是${var},而不要写成$var,这样更安全更好。

用户变量是字母、数字和下划线组成的字符串,长度不超过20个。

shell脚本中定义的变量会一直保持着它们的值,但在shell脚本结束时会被删除掉。

变量被引用时,需要加上美元符号,但是赋值时不要加美元符号。

使用`或者$()可以进行命令替换。

输出重定向:

>,把结果输入到文件。(清空重写)

>>,把结果追加到文件。

<,把文本读入命令。

<<,是一种手动输入,输入起始符号和结束符号一致,比如:

wc << EOF

Test1

Test2

Test3

EOF

|,把一个命令的输出作为另一个命令的输入。

expr命令操作符:

Arg1 | arg2,逻辑或操作,真返回arg1,假返回arg2

Arg1 & arg2,逻辑与操作,真返回arg1,假返回arg2

Arg 1 < arg2,真返回1,否则为0

Arg1 <= arg2,真返回1,否则为0

Arg1 = arg2,真返回1,否则为0

Arg1 != arg2,真返回1,否则为0

Arg1 >= arg2,真返回1,否则为0

Arg1 > arg2,真返回1,否则为0

Arg1 + arg2,求和。

Arg1 - arg2,求差。

Arg1 * arg2,求积。

Arg1 / arg2,求商。

Arg1 % arg2,求余数。

String : regexp,如果regexp匹配到了string中某个模式,返回匹配多少个。regexp可以是字符串,可以是使用了正则表达式的字符串。比如:expr abc : abc,则表示匹配3个(返回值),如果是expr abcde : a.*,则是匹配5个(返回值)。

Match string regexp,同上。

Substr string pos length,对stringpos位置开始(从1开始计数),length个长度的字符串进行输出。

Index string chars,在string中找chars字符串,如果有返回1,否则为0

Length string,返回string长度。

+ TOKEN,将TOKEN解释成字符串,即使是个关键字。

(EXPRESSION),返回EXPRESSION的值。

expr的有些操作符需要专一,比如expr 5 \* 2

类似expr的计算可以使用$[]方式。这种方式在使用*等符号时,是不需要转义的。

expr不能很好的解决浮点运算,可以使用替代方案:

bcbash计算器,是一种编程语言,bash计算器能识别:

数字(整数和浮点数)

变量(简单变量和数组)

注释(#或者/* */

表达式

函数

编程语句等

bc中的scale是小数点的位数,默认是0。在脚本中使用bc的例子:

#!/bin/bash

Var1=100

Var2=45

Var3=$(echo "scale=4;$var1 / $var2" | bc)

可以配合使用<<,如:

#!/bin/bash

Var1=10.46

Var2=43.67

Var3=33.2

Var4=71

Var5=$(bc << EOF

Scale = 4

A1 = ( $var1 * $var2 )

B1 = ( $var3 * $var4 )

A1 + b1

EOF

)

退出状态码是一个0~255的整数值,在结束命令时传给shell。可以捕获这个值并在脚本中使用。

一个成功结束的命令提出状态码是0。如果是有错的退出码,就是一个正数值。

如果想指定退出状态码,可以使用exit命令,如exit 5