Linux
Linux可划分为四部分: 1. Linux内核 2. GNU工具 3. 图形化桌面环境 4. 应用软件
Linux系统的核心是内核。内核控制着计算机系统上的所有硬件和软件,在必要时分配硬件, 并根据需要执行软件
内核主要负责以下四种功能:
- 系统内存管理
管理服务器上的可用物理内存,还可以创建和管理虚拟内存
- 软件程序管理
运行中的程序叫进程,内核创建第一个进程(init进程)来启动系统上所有其他进程
Linux操作系统的init系统采用了运行级,Linux操作系统有5个启动运行级
运行级为1时,只启动基本的系统进程以及一个控制台终端进程,称之为单用户模式。 单用户模式通常用来在系统有问题时进行紧急的文件系统维护。在这种模式下,仅有一个人(通常是系统管理员)能登录到系统上操作数据
标准的启动运行级是3,在这个运行级上大多数应用软件,比如网络支持程序都会启动
另一个Linux中常见的运行级是5。在这个运行级上系统会启动图形化的X Window系统,允许用户通过图形化桌面窗口登录系统
- 硬件设备管理
任何Linux系统需要与之通信的设备都需要在内核代码中加入其驱动程序代码。驱动程序代码相当于应用程序和硬件设备的中间人,允许内核与设备之间交换数据
在Linux内核中有两种方法用于插入设备驱动代码:
- 编译进内核的设备驱动代码
- 可插入内核的设备驱动模块
Linux系统将硬件设备当成特殊的文件,设备文件有3种分类:
- 字符型设备文件
处理数据时每次只能处理一个字符的设备。大多数类型的调制解调器和终端都是作为字符型设备文件创建的
- 块设备文件
处理数据时每次能处理大块数据的设备, 比如硬盘
- 网络设备文件
采用数据包发送和接收数据的设备,包括各种网卡和一个特殊的回环设备。这个回环设备允许Linux系统使用常见的网络编程协议同自身通信
Linux为系统上的每个设备都创建一种称为节点的特殊文件。与设备的所有通信都通过设备节点完成。每个节点都有唯一的数值对让Linux内核标识它。数值对包括一个主设备号和一个次设备号,类似的设备被划分到同样的主设备号下,次设备号用于标识主设备组下的某个特 定设备
- 文件系统管理
Linux内核支持通过不同类型的文件系统从硬盘中读写数据。除了自有的诸多文件系统外,Linux还支持从其他操作系统采用的文件系统中读写数据。内核必须在编译时就加入对所有可能用到的文件系统的支持
GNU工具
供Linux系统使用的这组核心工具被称为coreutils(core utilities)软件包, GNU coreutils软件包由三部分构成:1.用以处理文件的工具2.用以操作文本的工具3.用以管理进程的工具
shell是一种特殊的交互式工具,它为用户提供了启动程序、管理文件系统中的文件以及运行在Linux系统上的进程的途径。shell的核心是命令行提示符:输入文本命令,然后解释命令并在内核中执行
可以将多个shell命令放入文件中作为程序执行。这些文件被称作shell脚本。在命令行上执行的任何命令都可放进一个shell脚本中作为一组命令执行
Ctrl+Alt+[F1~F7]:切换到不同的虚拟控制台,Ubuntu使用F7- #setterm -background color
- /*更改终端背景颜色*/
- #setterm -foreground
- /*更改终端字体颜色*/
- #setterm -store
- /*恢复默认值*/
复制代码 文件和目录命令
文件命令
man命令用来访问存储在Linux系统上的手册页面。在想要查找的工具的名称前面输入man命令,就可以找到那个工具相应的手册条目
手册分配了9个内容区域:
- 1:可执行程序或shell命令
- 2:系统调用
- 3:库调用
- 4:特殊文件
- 5:文件格式与约定
- 6:游戏
- 7:概览、约定及杂项
- 8:超级用户和系统管理员命令
- 9:内核例程
Linux会在根驱动器上创建一些特别的目录,称为挂载点mount point。挂载点是虚拟目录中用于分配额外存储设备的目录
- #cd destination
- 切换到指定目录,没有指定则切换至用户主目录
- #pwd
- 查看当前目录
- -P:显示确定的路径,而不是链接路径,注意是大写
复制代码
- 绝对路径
从根目录 / 开始指定完整的路径名
- 相对路径
不从根目录开始,而以某目录名或特殊字符开始
- .:当前目录
- ..:上一层目录
- - :前一个工作目录
- ~ :目前使用者身份所在的主文件夹
ls:显示当前目录下的文件和目录- -a:全部的文件,连同隐藏文件一起列出
- -A:全部的文件,连同隐藏文件,但不包括 . 与 .. 这两个目录
- -d:仅列出目录本身,而不是列出目录内的文件数据
- -f:直接列出结果,而不进行排序(ls默认会以文件名排序)
- -F:根据文件、目录等信息,给予附加数据结构
- *:代表可可执行文件
- /:代表目录
- =:代表socket文件
- |:代表FIFO文件
- -h:将文件大小以人类较易读的方式(例如 GB, KB 等等)列出来
- -i:列出inode号码
- -l:长数据串行出,包含文件的属性与权限等等数据
- -n:列出UID与GID而非使用者与群组的名称
- -r:将排序结果反向输出,例如:原本文件名由小到大,反向则为由大到小
- -R:连同子目录内容一起列出来,等于该目录下的所有文件都会显示出来
- -S:以文件大小大小排序,而不是用文件名排序
- -t:依时间排序,而不是用文件名
- --color=never:不要依据文件特性给予颜色显示
- --color=always:显示颜色
- --color=auto:让系统自行依据设置来判断是否给予颜色
- --full-time:以完整时间模式(包含年、月、日、时、分)输出
- --time={atime,ctime} :输出 access 时间或改变权限属性时间(ctime)而非内容变更时间
复制代码 ls支持过滤器,就是在命令行参数后添加该字符串,可以使用通配符:
- ?:一个字符
- *:任意个字符
- [abcd] || [a~b]:包括中括号内的字符
- !:排除字符
修改时间文件 || 创建文件
每个文件在linux下面都会记录许多的时间参数,有三个主要的变动时间:
- modification time (mtime):当该文件的内容数据变更时,就会更新这个时间,内容数据指的是文件的内容,而不是文件的属性或权限
- status time (ctime):当该文件的状态(status)改变时,就会更新这个时间,权限与属性被更改都会更新这个时间
- access time (atime):当该文件的内容被取时,就会更新这个读取时间(access),也就是更新该文件的atime
默认的情况下,ls显示出来的是该文件的mtime
touch命令可用于修改文件或者目录的时间属性,包括存取时间和更改时间。若文件不存在,系统会建立一个新的文件- #touch filename
- /*可以使用以下参数来改变文件时间*/
- -a:仅修改访问时间access time
- -c:仅修改文件的时间,若该文件不存在则不创建新文件
- -d:后面可以为修改日期,也可以使用--date="日期或时间"
- -m:仅修改mtime
- -t:后面可以为修改日期,格式为[YYYYMMDDhhmm]
复制代码 复制文件- #cp source destination
- -a:相当于-dr --preserve=all的意思
- -d:若来源文件为链接文件的属性(link file),则复制链接文件属性而非文件本身
- -f:为强制(force)的意思,若目标文件已经存在且无法打开,则移除后再尝试一次
- -i:若目标文件(destination)已经存在时,在覆盖时会先询问动作的进行
- -l:进行硬链接(hard link)的链接文件创建,而非复制文件本身
- -p:连同文件的属性(权限、用户、时间)一起复制过去,而非使用默认属性(备份常用)
- -r[-R]:递回持续复制,用于目录的复制行为
- -s:复制成为软链接文件(symbolic link)
- -u:destination比source旧才更新destination,或destination不存在的情况下才复制
- --preserve=all:除了-p的权限相关参数外,还加入SELinux的属性, links,xattr等也复制了。如果来源文件有两个以上,则最后一个目的文件一定是目录
- 特殊符号可以用在相对文件路径
- #cp /etc/NetworkManager/NetworkManager.conf .
- 用.来表示当前工作目录
复制代码 链接文件
链接文件是Linux文件系统的一个优势。如需要在系统上维护同一文件的两份或多份副本, 除了保存多份单独的物理文件副本之外,还可以采用保存一份物理文件副本和多个虚拟副本的方 法。这种虚拟的副本就称为链接- #ln 目标路径 创建路径
- -s:不加任何参数就是hard link, -s就是symbolic link
- -f:如果目标文件存在时,就将目标文件直接移除后再创建
复制代码
- 实体链接(硬链接)
硬链接会创建独立的虚拟文件,其中包含了原始文件的信息及位置。但它们从根本上而言是同一个文件。引用硬链接文件等同于引用了源文件
- 符号链接(软链接)
软链接就是一个实实在在的文件,它指向存放在虚拟目录结构中某个地方的另一个文件。 这两个通过软链接在一起的文件,彼此的内容并不相同
重命名文件
在Linux中重命名文件称为moving,mv命令可以将文件和目录移动到另一个位置或重新命名
mv ~/Downloads/mongodb-org-server_7.0.5_amd64.deb /usr/local/bin- #mv source destination
- -f:force的意思,如果目标文件已经存在,不会询问而直接覆盖
- -i:若目标文件已经存在时,就会询问是否覆盖
- -u:若目标文件已经存在,且源文件比较新,才会更新
- /*可以使用mv来更名*/
- #mv test1 test2
- /*也可以使用mv命令移动文件位置并修改文件名称*/
- #mv /home/christine/Pictures/fzll /home/christine/fall
- 使用另一个指令rename可以更改mv ~/Downloads/mongodb-org-server_7.0.5_amd64.deb /usr/local/bin
- 大量文件的文件名
复制代码 删除文件- #rm filename
- -f:force的意思,忽略不存在的文件,不会出现警告讯息
- -i:互动模式,在删除前会询问使用者是否动作
- -r:递回删除,最常用在目录的删除,这是非常危险的选项
复制代码 目录命令
创建目录- #mkdir directoryname
- /*默认情况下目录需要一层一层的创建,不能一次性创建多层*/
- -p:会将上级不存在的目录一并自动创建
- -v:显示详细信息
- -m:运行用户指定创建新目录的权限
复制代码 删除目录- #rmdir directoryname
- /*只能删除空目录*/
- -p:将上层空的目录一并删除
- -v:显示详细信息
复制代码 查看文件
查看文件类型查看文件内容
cat(concatenate):由第一行开始显示文件内容- #cat filename
- -A:相当于-vET的整合选项,可列出一些特殊字符而不是空白
- -b:列出行号,空白行不标行号
- -n:列出行号,空白行也会有行号
- -E:将结尾的断行字符$显示出来
- -T:将[tab]按键以^I显示出来
- -v:列出一些看不出来的特殊字符
复制代码 more:一页一页的显示文件内容- #more filename
- +:从指定行开始输出
- -:指定每屏显示的行数
- +n:显示文件中的第n行之后的内容
- -n:显示文件中的前n行内容
- /*最后一行会显示出目前显示的百分比,而且还可以在最后一行输入一些有用的指令:*/
- space:代表向下翻一页
- Enter :代表向下翻一行
- /字符串:代表在这个显示的内容当中,向下搜寻这个字符串
- :f:立刻显示出文件名以及目前显示的行数
- q:离开more
- b或[ctrl]-b :代表往回翻页,只对文件有用
复制代码 less与more类似,但是它可以往前翻页- #less filename
- /*less更加灵活,有更多的指令:*/
- space:向下翻动一页
- pagedown:向下翻动一页
- pageup:向上翻动一页
- /字符串:向下搜寻字符串
- ?字符串:向上搜寻字符串
- n:重复上一个搜寻
- N:反向的重复上一个搜寻
- g:跳到文件开头
- G:跳到文件末尾
- q:离开less
复制代码 head:显示文件前几行- #head -n 100
- /*显示前100行*/
- #home -n -100
- /*最后100行不会显示*/
复制代码 tail:显示文件后几行- #tail -n 20
- /*显示最后20行*/
- #tail -n 20
- /*显示20行以后所有数据*/
- -f:在查看文件内容时实时追踪文件的变化,在文件更新时实时刷新输出,按下[ctrl]-c才会结束tail的追踪
复制代码 系统管理命令
进程命令
ps:显示运行在系统上所有程序的信息- /*默认情况只显示运行在当前控制台下的属于当前用户的进程*/
- -A 显示所有进程
- -N 显示与指定参数不符的所有进程
- -a 显示除控制进程(session leader)和无终端进程外的所有进程
- -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命令的版本号
复制代码
- UID:启动这些进程的用户
- PID:进程的进程ID
- PPID:父进程的进程号(如果该进程是由另一个进程启动的)
- C:进程生命周期中的CPU利用率
- STIME:进程启动时的系统时间
- TTY:进程启动时的终端设备
- TIME:运行进程需要的累计CPU时间
- CMD:启动的程序名称
- F:内核分配给进程的系统标记
- S:进程的状态(O代表正在运行;S代表在休眠;R代表可运行,正等待运行;Z代表僵化,进程已结束但父进程没有响应;T代表停止)
- PRI:进程的优先级(越大的数字代表越低的优先级)
- NI:谦让度值用来参与决定优先级
- ADDR:进程的内存地址
- SZ:假如进程被换出,所需交换空间的大致大小
- WCHAN:进程休眠的内核函数的地址
top:实时检测进程
- 第1行显示系统概况:当前时间、系统的运行时间、登录的用户数、系统的平均负载
平均负载有3个值:最近1分钟、最近5分钟和最近15分钟平均负载,值越大说明系统的负载越高
- 第2行显示进程概要信息:top命令的输出中将进程叫作任务task,有多少进程处在运行、休眠、停止或是僵化状态
- 第3行显示CPU概要信息:top根据进程的属主(用户还是系统)和进程的状态(运行、 空闲还是等待)将CPU利用率分成几类输出
- 第4行为物理内存,第5行为系统交换空间
- PID:进程ID
- USER:进程属主的名字
- PR:进程的优先级
- NI:进程的谦让度值
- VIRT:进程占用的虚拟内存总量
- RES:进程占用的物理内存总量
- SHR:进程和其他进程共享的内存总量
- S:进程的状态(D代表可中断的休眠状态,R代表在运行状态,S代表休眠状态,T代表 跟踪状态或停止状态,Z代表僵化状态)
- %CPU:进程使用的CPU时间比例
- %MEM:进程使用的内存占可用内存的比例
- TIME+:自进程启动到目前为止的CPU时间总量
- COMMAND:进程所对应的命令行名称,也就是启动的程序名
结束进程
进程之间通过信号来通信。进程的信号就是预定义好的一个消息,进程能识别 它并决定忽略还是作出反应
Linux进程信号- 1 HUP 挂起
- 2 INT 中断
- 3 QUIT 结束运行
- 9 KILL 无条件终止
- 11 SEGV 段错误
- 15 TERM 尽可能终止
- 17 STOP 无条件停止运行,但不终止
- 18 TSTP 停止或暂停,但继续在后台运行
- 19 CONT 在STOP或TSTP之后恢复执行
复制代码 要发送进程信号,必须是进程的属主或登录为root用户
kill命令可通过进程ID(PID)给进程发信号。默认情况下,kill命令会向命令行中列出的全部PID发送一个TERM信号。遗憾的是,只能用进程的PID而不能用命令名,所以kill命令有时并不好用- kill 进程号
- -l:列出所有信号名称
- -s:指定发送信号,默认情况发送15信号
- -p:只打印相关进程的进程号,而不发送任何信号
复制代码 killall命令非常强大,它支持通过进程名而不是PID来结束进程。killall命令也支持通配符,这在系统因负载过大而变得很慢时很有用- #killall http*
- 结束所有以http开头的进程
复制代码 检测磁盘命令
Linux文件系统将所有的磁盘都并入一个虚拟目录下。在使用新的存储媒 体之前,需要把它放到虚拟目录下。这项工作称为挂载
默认情况下,mount命令会输出当前系统上挂载的设备列表
mount命令提供如下四部分信息:
- 媒体的设备文件名
- 媒体挂载到虚拟目录的挂载点
- 文件系统类型
- 已挂载媒体的访问状态
要手动在虚拟目录中挂载设备,需要以root用户身份登录,或是以root用户身份运行sudo命令- #mount type device directory
- -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 给文件系统添加特定的选项:
- ro:以只读形式挂载。
- rw:以读写形式挂载。
- user:允许普通用户挂载文件系统。
- check=none:挂载文件系统时不进行完整性校验。
- loop:挂载一个文件
复制代码 从Linux系统上移除一个可移动设备时,不能直接从系统上移除,而应该先卸载
Linux上不能直接弹出已挂载的CD。如果在从光驱中移除CD时遇到麻烦,通常是因为该CD还挂载在虚拟目录里。先卸载它,然后再去尝试弹出- #umount [directory || device]
- umount命令支持通过设备文件或者是挂载点来指定要卸载的设备。如果有任何程序正在使用设备上的文件,系统就不会允许你卸载它
复制代码 df:查看所有已挂载磁盘的使用情况- #df
- -a:显示所有文件系统,包括系统专用的文件系统
- -h:以可读的格式显示磁盘使用情况,以MB、GB为单位显示
- -k:以kb为单位显示磁盘使用情况
- -m:以mb为单位显示磁盘使用情况
- -P:使用POSIX输出格式
- -T:显示文件系统类型
- -x:跳过不同文件系统上的目录,不予统计
- -l:计算所有硬链接的文件大小。
- -i:显示inode信息而非块使用量
复制代码
- Filesystem 设备的设备文件位置
- lk-blocks 能容纳多少个1024字节大小的块
- Used已用了多少个1024字节大小的块
- Available还有多少个1024字节大小的块可用
- Use%已用空间所占的比例
- Mounted on设备挂载到了哪个挂载点上
du:查看某个特定目录的磁盘使用情况
默认情况下,du命令会显示当前目录下所有的文件、目录和子目录的磁盘使用情况,它会以磁盘块为单位来表明每个文件或目录占用了多大存储空间- #du
- -a:显示目录下所有文件和子目录的大小,包括以.开头的隐藏文件
- -b:以字节为单位显示磁盘使用空间
- -c:额外显示所有目录或文件的总和
- -h:以可读的格式显示磁盘使用空间,例如以K、M、G为单位
- -s:只显示目录的总大小,不显示其下子目录和文件的大小
- -x:以目录树中从根目录开始的位置为标准,只显示当前目录下的文件和子目录的大小
- -l:统计硬链接所占用的磁盘空间大小
- -L:统计符号链接所指向的文件所占用的磁盘空间大小
复制代码 输出的列表是从目录层级的最底部开始,然后按文件、子目录、目录逐级向上
处理数据命令
排序数据
sort命令用于对数据进行排序,默认按照字符顺序进行升序排序- #sort filename
- -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=POS1 指定排序关键字,按照POS1字段来排序
- -M --month-sort 按月份排序
- -m --merge 将已排序数据文件合并
- -n --numeric-sort 按字符串数值来排序(并不转换为浮点数)
- -o --output=file 将排序结果写出到指定的文件中
- -o output.txt input.txt:将input.txt文件中的内容排序后输出到output.txt文件中
- -R --random-sort 按随机生成的散列表的键值排序
- --random-source=FILE 指定-R参数用到的随机字节的源文件
- -r --reverse 反序排序(升序变降序)
- -S --buffer-size=SIZE 指定使用的内存大小
- -s --stable 禁用最后重排序比较
- -T --temporary-directory=DIR 指定一个临时文件目录来存储临时工作文件
- -t --field-separator=SEP 指定分隔符,-t":"将冒号作为分隔符
- -z --zero-terminated 用NULL字符作为行尾,而不是用换行符
复制代码 搜索数据
grep命令会在输入或指定的文件中查找包含匹配指定模式的字符的行- #grep characterstring
- -v:反向搜索,查找不匹配该模式的行
- -n:显示对应的行号
- -c:显示一共有多少行匹配
- -r:递归搜索指定目录及子目录中的文件
- #grep -r "hello" /path/to/directory/
- -e:指定多个匹配模式
- #grep -e t -e f file1
- /*可以使用正则表达式*/
复制代码 egrep命令是grep的一个衍生,支持POSIX扩展正则表达式。POSIX扩展正则表达式含有更多的可以用来指定匹配模式的字符
fgrep则是另外一个版本,支持将匹配模式指定为用换行符分隔的一列固定长度的字符串。这样就可以把这列字符串放到一个文件中,然后在fgrep命令中用它在一个大型文件中搜索字符串
压缩数据
- gzip:压缩文件
- gzcat:查看压缩文件内容
- gunzip:解压文件
gzip命令会压缩在命令行指定的文件,也可以在命令行指定多个文件名或使用通配符来一次性批量压缩文件
归档数据
在Linux中,归档是将多个文件和目录打包成一个单独的归档文件(归档包)的过程。这个归档文件可以被存储在硬盘上,或者通过网络传输到其他系统或位置。归档文件通常用于备份、传输和存储多个文件和目录的集合,以便于在需要时进行恢复或访问- #tar 归档文件名 object1 object2 ...
- -A --concatenate 将一个tar归档文件追加到另一个tar归档文件
- -c --create 创建一个新的tar归档文件
- -C 切换到指定目录
- -d --diff --compare 检查归档文件和文件系统的不同之处
- --delete 从tar归档文件中删除
- -r --append 追加文件到tar归档文件末尾
- -t --list 列出tar归档文件的内容
- -u --update 将比tar归档文件中已有的同名文件新的文件追加到该tar归档文件中
- -x --extract 从tar归档文件中提取文件
- -f 输出结果到文件或设备file
- -j 将输出重定向给bzip2命令来压缩内容
- -p 保留所有文件权限
- -v 在处理文件时显示文件
- -z 将输出重定向给gzip命令来压缩内容
- /*这些选项经常合并到一起使用,可以用下列命令来创建一个归档文件:*/
- #tar -cvf test.tar test/ test2/
- /*上面的命令创建了名为test.tar的归档文件,含有test和test2目录内容,接着使用下列命令:*/
- #tar -tf test.tar
- /*列出tar文件test.tar的内容(但并不提取文件)。最后用命令:*/
- #tar -xvf test.tar
- /*从tar文件test.tar中提取内容,如果tar文件是从一个目录结构创建的,那整个目录结构都会在当前目录下重新创建*/
复制代码 tar命令是给整个目录结构创建归档文件的简便方法,这是Linux中分发开源程序源码文件所采用的普遍方法
shell
shell不单单是一种CLI(命令行界面,Command Line Interface for batch scripting),它是一个时刻都在运行的复杂交互式程序
系统启动什么shell程序取决于个人的用户ID配置。在/etc/passwd文件中的用户ID记录中列出了默认的shell程序- /*可以在一行中指定要依次运行的一系列命令,这可以通过命令列表来实现,只需要在命令间加入分号即可*/
- #pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls
- /*所有的命令依次执行,不过这不是进程列表。命令列表要想成为进程列表,这些命令必须包含在括号里*/
- #(pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls)
- 括号的加入使命令列表变成了进程列表,生成了一个子shell来执行对应的命令,括号也可以嵌套来创建子shell的子shel
复制代码 进程列表是一种命令分组command grouping。另一种命令分组是将命令放入花括号中, 并在命令列表尾部加上分号,语法为{ command; }。使用花括号进行命令分组并不会创建出子shell
子shell可以利用bash命令来生成。当使用进程列表或coproc命令时也会产生子shell
可以使用一个环境变量命令来查看是否生成子shell- #echo $BASH_SUBSHELL
- /*返回n便有几个子shell*/
复制代码 执行命令时,是否在子shell中执行会有一些区别,主要涉及环境变量和命令执行上下文:
如果命令在子shell中执行,那么该命令将不会影响当前shell的环境变量和执行上下文。这意味着在子shell中修改的环境变量和执行的操作不会影响父shell的环境。相反,如果命令在父shell中执行,那么它将对当前shell的环境产生影响。
另外,子shell的执行速度可能比在父shell中执行慢一些,因为需要额外的上下文切换和创建子进程
子shell用法
一个高效的子shell用法就是使用后台模式
在后台模式中运行命令可以在处理命令的同时让出CLI,以供它用
sleep命令接受一个参数,该参数是你希望进程等待(睡眠)的秒数。这个命令在脚本中常用于引入一段时间的暂停。sleep 10会将会话暂停10秒钟,然后返回shell CLI提示符- /*要想将命令置入后台模式,在命令末尾加上字符&*/
- #sleep 3000&
- [1] 2396
- 当它被置入后台,在shell CLI提示符返回之前,会出现两条信息:
- 1.后台作业(background job)号:1
- 2.后台作业的进程ID:2396
- /*jobs命令可以显示出当前运行在后台模式中的所有用户的进程(作业)*/
- #jobs
- [1]+ Running sleep 3000 &
- 作业号 当前状态 对应命令
- -l 额外显示作业的进程ID
- -n 仅显示上次显示后状态发生更改的作业
- -r:仅显示运行状态(running)的任务
- -s:仅显示停止状态(stopped)的任务
复制代码 在CLI中运用子shell的创造性方法之一就是将进程列表置入后台模式。既可以在子shell中进行繁重的处理工作,同时也不会让子shell的I/O受制于终端
协程
协程可以同时做两件事:它在后台生成一个子shell,并在这个子shell中执行命令- /*创建子shell并将命令置入后台模式*/
- #coproc sleep 10
- [1] 2544
- /*jobs命令能够显示出协程的处理状态*/
- #jobs
- [1]+ Running coproc COPROC sleep 10 &
- /*COPROC是coproc命令给进程起的名字。可以使用命令的扩展语法自己设置这个名字*/
- #coproc My_Job { sleep 10; }
- [1] 2570
- # jobs
- [1]+ Running coproc My_Job { sleep 10; } &
- 扩展语法写起来有点麻烦
- 必须确保在第一个花括号和命令名之间有一个空格。还必须保证命令以分号结尾。另外,分号和闭花括号之间也得有一个空格
复制代码 shell的内建命令
- 外部命令
也称文件系统命令,是存在于bash shell之外的程序,它们并不是shell 程序的一部分
当外部命令执行时,会创建出一个子进程。这种操作被称为衍生
外部命令ps可以很方便显示出它的父进程以及自己所对应的衍生子进程,作为外部命令,ps命令执行时会创建出一个子进程
当进程必须执行衍生操作时,它需要花费时间和精力来设置新子进程的环境。所以说外部命令多少还是有代价的
就算衍生出子进程或是创建了子shell,你仍然可以通过发送信号与其沟通
- 内建命令
不需要使用子进程来执行。它们已经和shell编译成了一体,作为shell工具的组成部分存在,不需要借助外部程序文件来运行
者不需要使用子进程来执行。它们已经和shell编译成了一 体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行
因为既不需要通过衍生出子进程来执行,也不需要打开程序文件,内建命令的执行速度要更快,效率也更高
有些命令即有内建命令还有外部命令
对于有多种实现的命令,如果想要使用其外部命令实现,直接指明对应的文件就可以了。 例如要使用外部命令pwd,可以输入/bin/pwd
history是一个内建命令,会跟踪使用过的命令,通常历史记录中会保存最近的1000条命令,可以唤回并重用历史列表中最近的命令,输入!!,然后按回车键就能唤出刚刚使用过的那条命令来使用
命令历史记录被保存在隐藏文件.bash_history中,它位于用户的主目录中。这里要注意的是, bash命令的历史记录是先存放在内存中,当shell退出时才被写入到历史文件中
可以在退出shell会话之前强制将命令历史记录写入.bash_history文件。要实现强制写入,可以使用 history -a
如果打开了多个终端会话,仍可以使用history -a命令在打开的会话中向.bash_history文件中添加记录,但是对于其他打开的终端会话,历史记录并不会自动更新。这是因为.bash_history文件只有在打开首个终端会话时才会被读取。要想强制重新读取.bash_history文件,更新终端会话的历史记录,可以使用history -n命令
可以唤回历史列表中任意一条命令。只需输入感叹号和命令在历史列表中的编号
alias是一个内建命令,命令别名允许你为常用的命令(及其参数)创建另一个名称,减少输入量
可以使用alias -p来查看当前当前可用的别名
创建别名:alias li='ls -li'
在定义好别名之后,你随时都可以在shell中使用它,就算在shell脚本中也没问题。 但命令别名属于内部命令,一个别名仅在它所被定义的shell进程中才有效
echo命令
echo 是一个在许多命令行环境中常用的命令,用于在终端输出文本或变量的值- -e:允许解释转义字符
- -n:不在输出后添加新行
- -E:不使用-e选项,即不解释转义字符
- -v:显示选项后面的值
复制代码 环境变量
很多程序和脚本都通过环境变量来获取系统 信息、存储临时数据和配置信息
bash shell用一个叫作环境变量environment variable的特性来存储有关shell会话和工作环境的信息。这项特性允许你在内存中存储数据,以便程序或shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法
在bash shell中环境变量分为两类
- 全局环境变量
全局环境变量对于shell会话和所有生成的子shell都是可见的,全局环境变量对那些所创建的子shell需要获取父shell信息的程序来说非常有用
系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量
要查看全局变量,可以使用env或printenv命令,查看个别环境变量的值,使用printenv,也可以使用echo显示变量的值。但在引用某个环境变量的时候,必须在变量前面加上一个美元符($)
- 局部环境变量
局部变量则只对创建它们的shell可见,在Linux系统并没有一个只显示局部环境变量的命令
set命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序。env和printenv命令同set命令的区别在于前不会对变量排序,也不会输出局部变量和用户定义变量
设置用户定义变量
一旦启动了bash shell或者执行一个shell脚本,就能创建在这个shell进程内可见的局部变量。可以通过等号给环境变量赋值,值可以是数值或字符串- /*创建局部环境变量*/
- #$my_variable
- /*定义局部环境变量*/
- #my_variable=Hello
- /*使用局部环境变量*/
- #echo $my_variable
- Hello
复制代码 echo用于在终端或命令行界面上输出文本或变量的值
如果要给变量赋一个含有空格的字符串值,必须用双引号来界定字符串的首尾,没有的话,bash shell会以为下一个词是另一个要执行的命令
所有的环境变量名均使用大写字母,涉及用户定义的局部变量时使用小写字母,这能够避免重新定义系统环境变量可能带来的灾难
变量名、等号和值之间没有空格,这一点非常重要。如果在赋值表达式中加上了空格, bash shell就会把值当成一个单独的命令
设置了局部环境变量后,就能在shell进程的任何地方使用它了。但如果生成了另外一个shell,它在子shell中就不可用
回到父shell时,子shell中设置的局部变量就不存在了
设置全局环境变量
创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局环境中,使用export命令来完成,变量名前无需加$- #my_variable="I am Global now"
- /*导出为全局环境变量*/
- #export my_variable
- /*创建子shell*/
- #bash
- /*在子shell中使用*/
- #echo $my_variable
- I am Global now
- /*修改子shell中全局环境变量并不会影响到父shell中该变量的值,使用export也无法改变*/
- #my_variable="NULL NOW"
- #echo $my_variable
- NULL NOW
- #exit
- /*父shell的环境变量并没有改变*/
- #echo $my_variable
- I am Global now
复制代码 删除环境变量
使用unset删除已存在的环境变量,在unset命令中引用环境变量时,不使用$- #echo $my_variable
- #I am Global now
- /*删除环境变量*/
- #unset my_variable
复制代码 要使用变量加$,要操作变量不加,这条规则的一个例外就是使用printenv显示某个变量的值
在子进程中删除了一个全局环境变量, 这只对子进程有效。该全局环境变量在父进程中依然可用
默认的shell环境变量
bash shell源自当初的Unix Bourne shell,因此也保留了Unix Bourne shell里定义的那些环境变量,下列为bash shell支持的Bourne变量:- CDPATH 冒号分隔的目录列表,作为cd命令的搜索路径
- HOME 当前用户的主目录
- IFS shell用来将文本字符串分割成字段的一系列字符
- MAIL 当前用户收件箱的文件名(bash shell会检查这个文件,看看有没有新邮件)
- MAILPATH 冒号分隔的当前用户收件箱的文件名列表(bash shell会检查列表中的每个文件,看看有没有新邮件)
- 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 match)时,包含了匹配到的模式和子模式
- 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
- COPROC
- 含有由shell函数生成的可能填充代码的数组变量
- 占用未命名的协进程的I/O文件描述符的数组变量
- DIRSTACK 含有目录栈当前内容的数组变量
- EMACS 设置为't'时,表明emacs shell缓冲区正在工作,而行编辑功能被禁止
- ENV 如果设置了该环境变量,在bash shell脚本运行之前会先执行已定义的启动文件(仅用于当bash shell以POSIX模式被调用时)
- EUID 当前用户的有效用户ID(数字形式)
- FCEDIT 供fc命令使用的默认编辑器
- FIGNORE 在进行文件名补全时可以忽略后缀名列表,由冒号分隔
- FUNCNAME 当前执行的shell函数的名称
- FUNCNEST 当设置成非零值时,表示所允许的最大函数嵌套级数(一旦超出,当前命令即被终止)
- GLOBIGNORE 冒号分隔的模式列表,定义了在进行文件名扩展时可以忽略的一组文件名
- GROUPS 含有当前用户属组列表的数组变量
- histchars 控制历史记录扩展,最多可有3个字符
- HISTCMD 当前命令在历史记录中的编号
- HISTCONTROL 控制哪些命令留在历史记录列表中
- HISTFILE 保存shell历史记录列表的文件名(默认是.bash_history)
- HISTFILESIZE 最多在历史文件中存多少行
- HISTTIMEFORMAT 如果设置了且非空,就用作格式化字符串,以显示bash历史中每条命令的时间戳
- HISTIGNORE 由冒号分隔的模式列表,用来决定历史文件中哪些命令会被忽略
- HISTSIZE 最多在历史文件中存多少条命令
- HOSTFILE 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环境变量
当在shell命令行界面中输入一个外部命令时,shell必须搜索系统来找到对应的程序。PATH环境变量定义了用于进行命令和程序查找的目录
输出中显示了有8个可供shell用来查找命令和程序,PATH中的目录使用冒号分隔。 如果命令或者程序的位置没有包括在PATH变量中,不使用绝对路径shell是无法找到的- PATH=$PATH:/home/christine/Scripts
- /*将目录添加到PATH环境变量,就可以在虚拟目录结构中的任何位置执行程序*/
复制代码 对PATH变量的修改只能持续到退出或重启系统
登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件,bash检查的启动文件取决于启动bash shell的方式。启动bash shell有3种方式:
- 登录时作为默认登录shell
- 作为非登录shell的交互式shell
- 作为运行脚本的非交互shell
登录式shell
当你登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里读取命令:
- /etc/profile
/etc/profile文件是系统上bash shell默认的主启动文件。系统上的每个用户登录时都会执行这个启动文件
剩下的启动文件都起着同一个作用:提供一个用户专属的启动文件来定义该用户所用到的环境变量。大多数Linux发行版只用这四个启动文件中的一到两个
$HOME表示的是某个用户的主目录,它和波浪号(~)的作用一样
- $HOME/.bash_profile
- $HOME/.bashrc
- $HOME/.bash_login
- $HOME/.profile
交互式shell
如果bash shell不是登录系统时启动的(比如是在命令行提示符下敲入bash时启动),那么你启动的shell叫作交互式shell
交互式shell不会像登录shell一样运行,但它依然提供了命令行提示符来输入命令。 如果bash是作为交互式shell启动的,它就不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件
.bashrc文件有两个作用:一是查看/etc目录下通用的bashrc文件,二是为用户提供一个定制自己的命令别名和私有脚本函数的地方
非交互式shell
系统执行shell脚本时用的就是这种shell,不同的地方在于它没有命令行提示符
bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进 程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件,shell会执行该文件里的命令,这通常包括shell脚本变量设置
环境变量持久化
如果升级了所用的发行版, 这个文件也会跟着更新,那你所有定制过的变量设置可就都没有了,最好在/etc/profile.d目录中创建一个以.sh结尾的文件,把所有新的或修改过的全局环境变量设置放在这个文件中。
在大多数发行版中,存储个人用户永久性bash shell变量的地方是HOME/.bashrc文件。这一点适用于所有类型的shell进程。但如果设置了BASH_ENV变量,那么除非它指向的是HOME/.bashrc,否则你应该将非交互式shell的用户变量放在别的地方
可以把自己的alias设置放在 $HOME/.bashrc启动文件中,使其效果永久化
数组变量
数组是能够存储多个值的变量。这些值可以单独引用,也可以作为整个数组来引用
环境变量数组的索引值都是从0开始,如果只写echo $mytest[2],bash会尝试将其解释为一个变量名,而不是一个数组元素- /*要给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔*/
- #mytest=(one two three four five)
- /*要引用一个单独的数组元素,就必须用代表它在数组中位置的数值索引值,索引值要用方括号括起来*/
- #echo ${mytest[2]}
- #three
- /*要显示整个数组变量,可用星号作为通配符放在索引值的位置*/
- #echo ${mytest[*]}
- #one two three four five
- /*也可以改变某个索引值位置的值*/
- #mytest[2]=3
- #one two 3 four five
- /*unset 数组名是删除整个数组,也可以删除其中某个值*/
- #unset mytest[2]
- #echo ${mytest[*]}
- #one two four five
复制代码 数组变量有时会让事情很麻烦,所以在shell脚本编程时并不常用。对其他shell而言,数组变量的可移植性并不好,如果需要在不同的shell环境下从事大量的脚本编写工作,这会带来很多不便
Linux文件权限
用户对系统中各种对象的访问权限取决于他们登录系统时用的账户。 用户权限是通过创建用户时分配的用户ID(User ID)来跟踪的,每个用户都有唯一的UID
Linux系统的/etc/passwd文件包含了一些与用户有关的信息- #more -1 /etc/passwd
- root:x:0:0:root:/root:/bin/bash
- 登录用户名:用户密码:UID:GID:用户的文本描述:用户HONE目录的位置:用户的默认shell
复制代码 Linux系统的用户密码在/etc/shadow文件中,只有root用户才能访问,它为系统上的每个用户账户都保存了一条记录
添加新用户- #useradd username
- -c 添加备注
- -d 后面指定用户登录时的主目录
- -D 查看默认值,不在命令行中指定具体的值,useradd命令就会使用默认值
- -s 后面指定用户的登录shell
- -G 后面指定用户的附加组,可以指定多个值,使用逗号隔开
- -e YYYY-MM-DD格式指定一个账户过期的日期
- -k 必须和-m一起使用,将/etc/skel目录的内容复制到用户的HOME目录
- -m 自动创建用户的主目录 默认情况不会自动创建
- -M 不创建用户主目录
- -n 创建一个与用户登录名同名的新组
- -f 设置密码过期的天数,设置为0则是禁用密码过期警告
- -u 手动设置UID
- -g 手动设置GID
- -r 创建系统账户
- -p 为用户账户指定默认密码
- # useradd -D
- GROUP=100 群组
- HOME=/home HOME目录
- INACTIVE=-1 密码过期后不会被禁用
- EXPIRE= 未设置过期日期
- SHELL=/bin/bash 默认shell
- SKEL=/etc/skel 该目录下的内容复制到用户的HOME目录下
- CREATE_MAIL_SPOOL=yes 为该用户在mail目录下创建一个用于接收邮件的文件
复制代码 useradd命令使用系统的默认值以及命令行参数来设置用户账户,系统默认值在/etc/default/useradd文件中
删除用户
默认情况下,userdel命令只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件- -r 删除用户的主目录及其所有文件
- -f 强制删除用户,即使该用户已登录
- -n 默认情况下userdel命令会删除用户主目录,如果要保留用户主目录,可以使用-n选项指定新的用户名,并将-r选项设置为false
复制代码 修改用户
- usermod:修改用户账户的字段,还可以指定主要组以及附加组的所属关系
- -l newname oldname 修改登录名
- -d newdirectory 修改主目录
- -s newshell 修改shell
- -g 修改用户所属主要组
- -G 修改用户所属附加组
- -L 锁定用户,无法登录
- -U 解锁用户
- -p 修改用户密码
复制代码 - passwd:修改用户密码,-e可强制用户下次登录时修改密码。可以先给用户设置一个简单的密码,之后再强制在下次登录时改成他们能记住的更复杂的密码
chpasswd:从一个文件中读取用户和密码的组合,文件中的每一行包含一个用户名和对应的密码,文件格式应该为“username:password”
- chsh:快速修改默认的用户登录shell,使用时必须用shell的全路径名作为参数
chfn:更改finger命令显示的信息。这些信息存储在/etc/passwd文件中,并由finger程序显示- -f 设置姓名
- -h 设置电话号码
- -o 设置办公室地址
- -p 设置办公室电话号码
复制代码 如果未指定任何参数,chfn命令将进入问答式界面,提示每个字段,用户可以在提示符下输入新信息,也可以按返回使字段保持不变。输入关键字None使字段为空
chage:管理用户账号有效期
chage命令的日期值可以用下面两种方式中的任意一种:
- YYYY-MM-DD格式的日期
- 从1970年1月1日起到该日期天数的数值
- -d 设置上次修改密码到现在的天数
- -E 设置密码过期的日期
- -I 设置密码过期到锁定账户的天数
- -m 设置修改密码之间最少要多少天
- -W 设置密码过期前多久开始出现提醒信息
复制代码 过期的账户跟锁定的账户很相似:账户仍然存在, 但用户无法用它登录
群组
组权限允许多个用户对系统中的对象(比如文件、目录或设备等)共享一组共用的权限,每个组都有唯一的GID,和UID类似,组名也是唯一的
/etc/group文件包含系统上用到的每个组的信息- #more -1 /etc/group
- root:x:0:
- 组名:组密码:GID:属于该组的用户列表
复制代码 创建新组- #groupadd groupname
- -g 指定GID
- -r 创建系统组,系统组GID小于500
复制代码 更改了已登录系统账户所属的用户组,该用户必须登出系统后再登录,组关系的更改才能生效
修改组- #groupmod groupname
- -g 设置新GID
- -o 允许使用重复GID
- -n 设置新组名
复制代码 文件权限
- #ls -l
- drwxr-xr-x. 2 xwj xwj 6 Jan 21 13:04 Desktop
复制代码 第1个字符代表:
- d是目录
- -是文件
- l是链接文件link file
- b是可供储存的接口设备,例如硬盘,U盘[块设备]
- c是串行接口设备,例如键盘、鼠标[字符型设备]
- n是网络设备
接下来的字符以3个为一组,均为rwx的组合,无权限使用-代替:
- r read:可读取此一文件的实际内容,如读取文本文件的文字内容等
- w write:可以编辑、新增或者是修改该文件的内容(但不含删除该文件)
- x execute:该文件具有可以被系统执行的权限
从左到右的3组权限分别为User、Group、Others的权限
- 2表示有多少文件名硬链接到此文件,每个文件至少有一个硬链接,通常这个硬链接就是文件名本身
- 第1个xwj表示这个文件或目录的拥有者账号
- 第2个xwj表示这个文件的所属群组
- 193为文件的大小,单位为bytes
- 4月 1 2020为文件最近修改日期
内容分别为月 日 时间,如果这个文件被修改的时间距离现在太久,那么时间部分仅显示年份
如果想要显示完整的时间格式,ls -l --full-time就能够显示出完整的时间格式
- .bash_profile为文件名
目录与文件的权限意义并不相同,这是因为目录与文件所记录的数据内容不相同
文件是存放实际数据的所在,目录主要的内容在记录文件名
针对目录时:
- r read contents in directory:表示具有读取目录结构清单的权限,所以当你具有读取一个目录的权限时,表示你可以查询该目录下的文件名数据。就可以利用 ls 这个指令将该目录的内容列表显示出来
- w modify contents of directory:它表示你具有异动该目录结构清单的权限,也就是下面这些权限:
- 创建新的文件与目录
- 删除已经存在的文件与目录(不论该文件的权限为何)
- 将已存在的文件或目录进行更名
- 搬移该目录内的文件、目录位置。总之,目录的w权限就与该目录下面的文件名异动有关
- x access directory:目录不可以被执行,目录的x代表的是使用者能否进入该目录成为工作目录的用途,所谓的工作目录work directory就是你目前所在的目录,当你登陆Linux时,你所在的主文件夹就是你当下的工作目录
文件是一堆文件数据夹,目录是一堆抽屉,可以将数据夹分类放置到不同的抽屉去,因此抽屉最大的目的是拿出/放入数据夹
仅拥有r权限,没有x权限是无法执行文件或进入目录的
有x就可以执行了,r是可选的,如果没有r,按Tab无法自动补齐文件名
改变文件属性与权限
touch命令用分配给我的用户账户的默认权限创建了这个文件,umask命令可以显示和设置这个默认权限第1位代表粘着位,是一项特别的安全特性,后面3位是文件或目录对应的8进制值- 权限 二进制 八进制 描述
- --- 000 0 没有任何权限
- --x 001 1 只有执行权限
- -w- 010 2 只有写入权限
- -wx 011 3 有写入和执行权限
- r-- 100 4 只有读取权限
- r-x 101 5 有读取和执行权限
- rw- 110 6 有读取和写入权限
- rwx 111 7 有全部权限
复制代码 umask的值是掩码,数字是需要减掉的值,022==755
更改权限直接在umask后输入数字即可
改变权限
chmod命令用于改变文件和目录的安全性设置- -r 递归改变指定目录及其下所有文件和子目录的权限
- -v 显示详细信息
复制代码
- 数字类型改变文件权限
r:4,w:2,x:1符号类型改变文件权限
- u:user,g:group,o:others,a:all
- chmod u=rwx,go=rx .bashrc
- 也可以使用+来加上某个权限
- a+r
- 也可以使用-来 减去某个权限
- a-r
复制代码 改变所属关系
chown :改变文件拥有者
change owner,在/etc/passwd这个文件中有纪录的使用者名称才能改变
可用登录名或UID来指定文件的新属主- #chown 账号名 文件或目录
- /*可以以只更改拥有者,也可以同时修改拥有者和群组*/
- #chown 帐号名:群组名 文件或目录
- -r 递归更改目录及其以下所有文件和子目录的所有者和群组
- -h 改变该文件的所有符号链接文件的所属关系
复制代码 chgrp :改变文件所属群组
change group,被改变的群组名称必须要在/etc/group文件内存在,否则就会显示错误- #chgrp 群组名 文件或目录
- -r 不多说
- -v 显示指令执行过程
- -h 只对符号链接的文件作修改,而不更改其他任何相关文件
复制代码 文件系统操作
创建分区
fdisk用于来帮助管理安装在系统上的任何存储设备上的分区
创建新磁盘分区最麻烦的事情就是找出安装在Linux系统中的物理磁盘,老式的IDE驱动器,Linux使用的是/dev/hdx。其中x表示一个字母,具体是什么要根据驱动器的检测顺 序(第一个驱动器是a,第二个驱动器是b,以此类推)
对于较新的SATA驱动器和SCSI驱动器,Linux使用/dev/sdx。其中的x具体是什么也要根据驱动器的检测顺序(同上,第一个驱动器是a,第二个驱动器是b,以此类推)。在格式化分区之前,最好再检查 一下是否正确指定了驱动器- #fdisk
- -l 列出当前系统中的所有磁盘设备以及分区表
- -u 以扇区为单位显示分区大小
- /*交互命令*/
- l 显示可用的分区类型
- m 显示命令选项
- n 创建分区
- d 删除分区
- p 显示当前分区表
- w 退出,保存更改
- q 退出,不保存更改
复制代码 创建文件系统
在将数据存储到分区之前,你必须用某种文件系统对其进行格式化,这样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文件系统
复制代码 并非所有文件系统工具都已经默认安装了,想知道某个文件系统工具是否可用,可以使用type命令
文件系统挂载与卸载
为分区创建了文件系统之后,下一步是将它挂载到虚拟目录下的某个挂载点,这样就可以将数据存储在新文件系统中
- 单一文件系统不应该被重复挂载在不同的挂载点(目录)中
- 单一目录不应该重复挂载多个文件系统
- 要作为挂载点的目录,理论上应该都是空目录
- #mount -t 文件系统类型 -o 选项 设备文件 挂载点
- -o:后面可以接一些挂载时额外加上的参数,比方说帐号、密码、读写权限等:
- async, sync:此文件系统是否使用同步写入(sync)或非同步(async)的内存机制,默认为async
- atime,noatime: 是否修订文件的读取时间(atime),为了性能某些时刻可使用noatime
- ro, rw:挂载文件系统成为只读(ro)或可读写(rw)
- auto, noauto:是否允许此filesystem被以mount -a自动挂载(auto)
- dev, nodev:是否允许此filesystem上可创建设备文件,dev为可允许
- suid, nosuid:是否允许此filesystem含有suid/sgid的文件格式 exec, noexec:是否允许此filesystem上拥有可执行binary文件 user, nouser:是否允许此filesystem让任何使用者执行mount,一般来说,mount仅有root可以进行,但下达user参数,则可让一般user也能够对此partition进行mount
- defaults:默认值为:rw, suid, dev, exec, auto, nouser, and async
- remount:重新挂载,在系统出错或重新更新参数时很有用
- /*卸载已挂载的文件系统*/
- #umount 挂载点
- -f 忽略任何错误,强制将文件系统从挂载点卸载
- -l 将文件系统设置为只读模式,然后卸载
- -r 显示详细信息
复制代码 文件系统的检查与修复
fsck命令能够检查和修复大部分类型的Linux文件系统- #fsck filesystem
- -a 自动修复文件系统
- -A 依照/etc/fstab配置文件的内容,检查文件内所列的全部文件系统
- -P 当搭配"-A"参数使用时,则会同时检查所有的文件系统
- -r 互动模式,在执行修复时询问问题,让用户得以确认并决定处理方式
- -R 当搭配"-A"参数使用时,则会略过/目录的文件系统不予检查
- -s 依序执行检查作业,而非同时执行
- -t 文件系统类型 指定要检查的文件系统类型
- -V 显示指令执行过程
复制代码 可以在命令行上列出多个要检查的文件系统。文件系统可以通过设备名、在虚拟目录中的挂载点以及分配给文件系统的唯一UUID值来引用
只能在未挂载的文件系统上运行fsck命令。对大多数文件系统来说,你只需卸载文件系统来进行检查,检查完成之后重新挂载就好了。但因为根文件系统含有所有核心的Linux 命令和日志文件,所以你无法在处于运行状态的系统上卸载它
逻辑卷管理
Linux逻辑卷管理器(logical volume manager,LVM)软件包可以让你在无需重建整个文件系统的情况下,轻松地管理磁盘空间
逻辑卷管理的核心在于如何处理安装在系统上的硬盘分区。在逻辑卷管理里,硬盘称作物理卷(physical volume,PV)。每个物理卷都会映射到硬盘上特定的物理分区
多个物理卷集中在一起可以形成一个卷组(volume group,VG)。逻辑卷管理系统将卷组视为一个物理硬盘,但卷组可能是由分布在多个物理硬盘上的多个物理分区组成的。卷组提供了一个创建逻辑分区的平台,而这些逻辑分区则包含了文件系统
逻辑卷(logical volume,LV)为Linux提供了创建文件系统的分区环境,作用类似于到目前为止Linux中的物理硬盘分区。Linux系统将逻辑卷视为物理分区
可以使用任意一种标准Linux文件系统来格式化逻辑卷,然后再将它加入Linux虚拟目录中的 某个挂载点
如果你给系统添加了一块硬盘,逻辑卷管理系统允许你将它添加到已有卷组,为某个已有的卷组创建更多空间,或是创建一个可用来挂载的新逻辑卷
快照
在逻辑卷在线的状态下将其复制到另一个设备
LVM2允许创建在线逻辑卷的可读写快照。有了可读写的快照,就可以删除原先的逻辑卷, 然后将快照作为替代挂载上。这个功能对快速故障转移或涉及修改数据的程序试验(如果失败, 需要恢复修改过的数据)非常有用
条带化
可跨多个物理硬盘创建逻辑卷。当Linux LVM将文件写入逻辑卷时,文件中的数据块会被分散到多个硬盘上。每个后继数据块会被写到下一个硬盘上
条带化有助于提高硬盘的性能,因为Linux可以将一个文件的多个数据块同时写入多个硬盘, 而无需等待单个硬盘移动读写磁头到多个不同位置。这个改进同样适用于读取顺序访问的文件, 因为LVM可同时从多个硬盘读取数据
LVM条带化会增加文件因硬盘故障而丢失的概率,单个硬盘故障可能会造成多个逻辑卷无法访问
镜像
镜像是一个实时更新的逻辑卷的完整副本。当创建镜像逻辑卷时,LVM会将原始逻辑卷同步到镜像副本中。根据原始逻辑卷的大小,这可能需要一些时间才能完成。 一旦原始同步完成,LVM会为文件系统的每次写操作执行两次写:一次写入到主逻辑卷,一次写入到镜像副本,会降低系统的写入性能
使用Linux LVM
定义物理卷
将硬盘上的物理分区转换成Linux LVM使用的物理卷区段
在fdisk命令中创建基本Linux分区后,使用t命令将分区类型改为8e,分区类型8e表示这个分区将会被用作Linux LVM系统的一部分,而不是一个直接的文件系统- /*将磁盘分区转换为物理卷*/
- #pvcreate /dev/sdb1
- /*显示已创建的物理卷列表*/
- #pvdisplay
复制代码 创建卷组
从物理卷中创建一个或多个卷组,究竟要为系统创建多少卷组并没有既定的规则, 可以将所有的可用物理卷加到一个卷组,也可以结合不同的物理卷创建多个卷组- #vgcreate 卷组名 物理卷名
- -l 卷组上允许创建的最大逻辑卷数
- -p 卷组中允许添加的最大物理卷数
- -v 显示执行过程
- /*显示卷组详细信息*/
- #vgdisplay 卷组名
复制代码 创建逻辑卷
创建一个或多个卷组后,就可以创建逻辑卷,Linux系统使用逻辑卷来模拟物理分区,并在其中保存文件系统
Linux系统会像处理物理分 区一样处理逻辑卷,允许你定义逻辑卷中的文件系统,然后将文件系统挂载到虚拟目录上- #lvcreate
- -c --chunksize 指定快照逻辑卷的单位大小
- -C --contiguous 设置或重置连续分配策略
- -i --stripes 指定条带数
- -I --stripesize 指定每个条带的大小
- -l --extents 指定分配给新逻辑卷的逻辑区段数,或者要用的逻辑区段的百分比
- -L --size 指定分配给新逻辑卷的硬盘大小
- --minor 指定设备的次设备号
- -m --mirrors 创建逻辑卷镜像
- -M --persistent 让次设备号一直有效
- -n --name 指定新逻辑卷的名称
- -p --permission 为逻辑卷设置读/写权限
- -r --readahead 设置预读扇区数
- -R --regionsize 指定将镜像分成多大的区
- -s snapshot 创建快照逻辑卷
- /*显示逻辑卷详细信息*/
- #lvdisplay
复制代码 创建文件系统
使用相应的命令行程序来创建所需要的文件系统
然后使用mount命令将这个卷挂载到虚拟目录中
修改LVM- #vgchange 激活和禁用卷组
- #vgremove 删除卷组
- #vgextend 将物理卷加到卷组中
- #vgreduce 从卷组中删除物理卷
- #lvextend 增加逻辑卷的大小
- #lvreduce 减小逻辑卷的大小
复制代码 安装软件程序
centos是基于Red Hat的系统,使用- #yum options command package
- -h 帮助
- -y 安装过程选择时全部为yes
- 常用命令包括:
- 安装install
- 更新update 升级upgrapde 更新会保留旧版本的package,升级不会
- 检查check 删除remove
- 查看某个特定软件包的详细信息 yum list package
- 列出系统上已安装的包yum list installed
复制代码 使用yum安装和卸载软件的前提是软件包必须是rpm格式,可以使用yum clean all清除所有,yum clean headers清除缓存目录下的headers,这些headers是用于描述软件包信息的元数据,yum clean packages清除下载的rpm包
yum是在安装发行版的时候设置的软件仓库,yum repolist可以查看现在正从哪些仓库中获取软件
如果仓库中没有需要的软件,可以编辑配置文件。yum的仓库定义文件位于 /etc/yum.repos.d。需要添加正确的URL,并获得必要的加密密钥
使用编辑器
vim编辑器
Unix系统最初的编辑器- /*为vim设置别名*/
- #alias vi=vim
- #alias vi
- alias vi='vim'
复制代码 which命令用于在PATH环境变量中指定的目录中查找可执行文件,并返回该文件的绝对路径。它的作用是快速定位到可执行文件的实际位置,避免因环境变量设置的错误导致无法找到正确的执行文件- /*查找vim的绝对路径*/
- # which vi
- alias vi='vim'
- /usr/bin/vim
- /*查看*/
- #ls -l /usr/bin/vim
- -rwxr-xr-x. 1 root root 2337208 Dec 16 2020 /usr/bin/vim
- 文件权限组 硬链接数量 所有者 所属组 文件大小[单位byte] 文件的最后修改日期 文件的绝对路径
复制代码 如果vim程序被设置了链接,它可能会被链接到一个功能较弱的编辑器。所以最好 还是检查一下链接文件- #vim [filename]
- 如在启动vim时未指定文件名,或者这个文件不存在,vim会开辟一段新的缓冲区域来编辑
复制代码 vim编辑器有两种操作模式:普通模式和插入模式,当你刚打开要编辑的文件或新建一个文件时,vim编辑器会进入普通模式。在普通模式中,vim编辑器会将按键解释成命令,i进入插入模式,ESC进入普通模式
移动命令
- h:左移 l:右移
- j:下移 k:上移
- PageUp或Ctrl+B:上翻一屏
- PageDown或Ctrl+F:下翻一屏
- gg:第一行
- G:最后一行
- number G:第n行
在普通模式下有个特别的功能叫命令行模式。命令行模式提供了一个交互式命令行,可以输入额外的命令来控制vim的行为。,在普通模式下按下冒号键,进入命令行模式,光标会移动到消息行,然后出现冒号,等待输入命令
- q:如果未修改缓冲区数据,退出
- q!:取消所有对缓冲区数据的修改,退出
- w filename:将文件保存到另一个文件中
- wq:将缓冲区数据保存到文件中并退出
编辑命令
- x:删除当前所在字符
- dw:删除所在单词
- dd:删除所在行
- d$:删除当前所在位置到行尾的内容
- j:删除行尾换行符
- u:撤销前一编辑命令
- a:在当前光标后追加数据
- A:在当前光标所在行行尾追加数据
- r char 用char替换当前光标所在位置的单个字符
- R text 用text覆盖当前光标所在位置的数据,直到按下ESC键
查找和替换命令
- /text:查找文本
- s/old/new/g:一行命令替换所有old
- :n,ms/old/new/g:替换行号n和m之间所有old
- :%s/old/new/g:替换整个文件中的所有old
nano编辑器
- CTRL+C:显示光标在文本编辑缓冲区中的位置
- CTRL+G:显示nano的主帮助窗口
- CTRL+K:剪切文本行,并将其保存在剪切缓冲区
- CTRL+U:将剪切缓冲区中的内容放入当前行
- CTRL+O:将当前文本编辑缓冲区的内容写入文件
- CTRL+R:将文件读入当前文本编辑缓冲区
- CTRL+T:启动可用的拼写检查器
- CTRL+Y:翻动到文本编辑缓冲区中的上一页内容
- CTRL+V:翻动到文本编辑缓冲区中的下一页内容
- CTRL+W:在文本编辑缓冲区中搜索单词或短语
- CTRL+X:关闭当前文本编辑缓冲区,退出nano
构建shell基本脚本
shell脚本的关键在于输入多个命令并处理每个命令的结果,甚至需要将一个命令的结果传给另一个命令命令之间使用分号隔开,可以将这些命令组合成一个简单的文本文件,这样就不需要在命令行中手动输入。在需要运行这些命令时,只用运行这个文本文件
使用文本编辑器来创建shell脚本文件
#用作注释行,shell并不会处理shell脚本中的注释行
shell脚本文件的第一行是个例外,#后面的惊叹号会告诉shell用哪个shell来运行脚本- #gvim test
- /*图形化vim*/
- #!/bin/bash
- echo This script displays the date and who's logged on
- date
复制代码 在编写好脚本文件后,需要编写PATH来让shell查找到
- 将shell脚本文件所处的目录添加到PATH环境变量中
- #PATH=$PATH:/所在目录
- #bash test
- This script displays the date and whos logged on
- Wed Jan 31 15:22:00 CST 2024
- xwj :0 2024-01-21 13:04 (:0)
- root tty2 2024-01-28 13:01
- xwj pts/1 2024-01-31 14:10 (:0)
复制代码 - 在提示符中用绝对或相对文件路径来引用shell脚本文件
- #./test
- bash: ./test: Permission denied
- /*拒绝权限*/
复制代码 最后要注意文件的权限组
在脚本中添加自己的文本消息,可以在echo命令后面加上了一个字符串,该命令就能显示出这个文本字符串- #echo This is a test
- This is a test
复制代码 默认情况下,不需要使用引号将要显示的文本字符串划定出来
echo命令可用单引号或双引号来划定文本字符串。如果在字符串中用到了它们,需要在文本中使用其中一种引号,而用另外一种来将字符串划定起来- #echo Let's see if this'll work
- Lets see if thisll work
- /*引号无法正常显示*/
- #echo "This is a test to see if you're paying attention"
- This is a test to see if you're paying attention
- #echo 'Rich says "scripting is easy".'
- Rich says "scripting is easy"
复制代码 如果想把文本字符串和命令输出显示在同一行中,使用echo -n
如果在字符串的两侧使用引号,保证要显示的字符串尾部有一个空格
使用变量
变量允许临时性地将信息存储在shell脚本中, 以便和脚本中的其他命令一起使用
可以在script内使用环境变量,使用$来引用
用户变量可以是任何由字母、数字或下划线组成的文本字符串,长度不超过20个,用户变量区分大小写,使用等号将值赋给用户变量。在变量、等号和值之间不能出现空格
shell脚本会自动决定变量值的数据类型。在脚本的整个生命周期里,shell脚本中定义的变量会一直保持着它们的值,在shell脚本结束时会被删除,也使用$来引用- day=1
- echo $day after
- /*输出*/
- 1 after
- /*可以使用变量给变量赋值*/
- da=$day
- 没有$,shell会将变量名解释为普通的文本字符串
复制代码 命令替换
有两种方法可以将命令输出赋给变量:
shell会运行命令替换符号中的命令,并将其输出赋给变量test,使用$test等价于使用date命令
命令替换会创建一个子shell来运行对应的命令。子shell是由运行该脚本的shell所创建出来的一个独立的子shell。正因此,由该子shell所执行命令是无法使用脚本中所创建的变量的。 在命令行提示符下使用路径./运行命令的话,也会创建出子shell;要是运行命令的时候不加入路径,就不会创建子shell。如果你使用的是内建的shell命令,并不会涉及子shell。 在命令行提示符下运行脚本时一定要留心
重定向输入和输出
输出重定向
bash shell使用>来实现- #command>outputfile
- /*example*/
- #date>test
- #cat test
- Wed Jan 31 15:33:56 CST 2024
复制代码 如果不想覆盖文件原有内容,使用>>来追加数据
输入重定向
将文件内容重定向到命令,使用 < 来实现- #wc<test
- 1 6 29
- wc命令可以对数据进行计数,默认情况分别输出行数、次数、字节数
复制代码 可以在if语句中用双括号命令,也可以在脚本中的普通命令里使用来赋值- #wc<<EOF
- > 1234
- > 1234
- > 1234
- > EOF
- 3 3 15
复制代码 不需要将双括号中表达式里的大于号转义,这是双括号命令提供的另一个高级特性
双方括号命令提供了针对字符串比较的高级特性,支持模式匹配
在模式匹配中,可以定义一个正则表达式来匹配字符串值
双方括号在bash shell中工作良好。不过要小心,不是所有的shell都支持双方括号
case命令
- /*rpm通过过Red Hat包管理系统对系统上安装的软件包进行管理,-qa将生成已安装包的列表,结果输出重定向到rpm.list,然后输入重定向到sort,按字母顺序进行排序*/
- #rpm -qa>rpm.list
- #sort<rpm.list
- #more rpm.list
- /*管道连接*/
- #rpm -qa|sort|more
复制代码
- case命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么shell会执行为该模式指定的命令
- 可以通过竖线操作符在一行中分隔出多个模式模式
- 星号会捕获所有与已知模式不匹配的值
case命令提供了一个更清晰的方法来为变量每个可能的值指定不同的选项
更多结构化命令
for命令在list参数中需要提供迭代中要用到的一系列值。可以通过几种不同的方法指定列表中的值
在每次迭代中,变量var会包含列表中的当前值。第一次迭代会使用列表中的第一个值,第 二次迭代使用第二个值,以此类推,直到列表中的所有值都过一遍
读取列表中的值- result=$[1+5]
- 使用美元符和方括号来将数学表达式围起来,使用方括号就不用担心shell会误解符号
复制代码 在最后一次迭代后,$test变量的值会在shell脚本的剩余部分一直保持有效。它会一直保持最后一次迭代的值,除非修改了它
如果值中带有单引号,有两种办法解决:
- 使用转义字符(反斜线)来将单引号转义
- 使用双引号来定义用到单引号的值
for循环假定每个值都是用空格分割的。 如果有包含空格的数据值需要使用双引号圈起来,在某个值两边使用双引号时,shell并不会将双引号当成值的一部分
从变量读取列表- #bc -q
- var1=10-2
- print var1
- 8
复制代码 从命令读取值
可以用命令替换来执行任何能产生输出的命令,然后在for命令中使用该命令的输出- /*编写shell脚本*/
- #!/bin/bash
- var1=$(echo "scale=4; 3.44 / 5" | bc)
- echo The answer is $var1
- /*output*/
- #./test
- The answer is .6880
复制代码 更改字段分隔符
环境变量IFS定义bash shell用作字段分隔符的一系列字符
默认情况下,bash shell会将下列字符当作字段分隔符:
在处理含有空格的数据时,可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段分隔符的字符- #!/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
- )
- echo The final answer for this megs is $var5
- /*使用脚本,这个报错应该就是警告性错误,反正脚本能运行,解决不了一点*/
- #./test
- ./test: line 20: warning: here-document at line 14 delimited by end-of-file (wanted `EOF')
- ./test: line 18: warning: here-document at line 13 delimited by end-of-file (wanted `EOF')
- (standard_in) 5: illegal character: O
- (standard_in) 5: syntax error
- The final answer for this megs is 2813.9882
复制代码 用通配符读取目录
可以用for命令来自动遍历目录中的文件。进行此操作时,必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展匹配。文件扩展匹配是生成匹配指定通配符的文件名或路径名的过程- 0 命令成功结束
- 1 一般性未知错误
- 2 不适合的shell命令
- 126 命令不可执行
- 127 没找到命令
- 128 无效的退出参数
- 128+x 与Linux信号x相关的严重错误
- 130 通过Ctrl+C终止的命令
- 255 正常范围之外的退出状态码
复制代码 在Linux中,目录名和文件名中包含空格是合法的。要适应这种情况,应该将$file变量用双引号圈起来。如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生
可以在数据列表中放入任何东西。即使文件或目录不存在,for语句也会尝试处理列表中的内容,所以最好先确定文件或目录是否存在
C语言风格的for命令
bash shell也支持一种for循环,它看起来跟C语言风格的for循环类似,但有一些细微的不同- if command
- then
- commands
- #和代码块一样,不是只能一条语句
- fi
- #和cpp一样,分号为结束,因此可以这样写
- if command; then
- command1; command2; fi
复制代码 有些部分并没有遵循bash shell标准的for命令:
- 变量赋值可以有空格
- 条件中的变量不以美元符开头
- 迭代过程的算式未用expr命令格式
- if command
- then
- commands
- else
- commands
- fi
- #变种if-else
复制代码 脚本中重定向输出和输入
可以在脚本中用STDOUT和STDERR文件描述符以在多个位置生成输出,只要简单地重定向相应的文件描述符就行
临时重定向- #!/bin/bash
- user=xwj
- if grep $user /etc/passwd
- then
- echo good very good
- ls -a /home/$user/.b*
- else
- echo The user $user does not exist on this system
- fi
复制代码 永久重定向
如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很烦琐
可以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符
exec命令会启动一个新shell并将文件描述符重定向到文件- !/bin/bash
-
- tuser=NoSuchUser
- if grep $tuser /etc/passwd
- then #如果登录名存在
- echo "The user $user exists on this system."
- else #如果登录名不存在
- echo "The user $user does not exist on this system."
- if ls -d /home/$user/ #如果登录名不存在,但是用户目录存在
- then
- echo "However, $user has a directory."
- fi
- fi
复制代码 重定向输入- if command
- then
- commands
- elif command
- # 如果elif后命令退出状态码为0.执行then部分,否则退出
- then
- commands
- fi
- #使用elif可以简写上面的嵌套,其实就只把else和if简写为elif
- if grep $user /etc/passwd
- then #如果登录名存在
- echo "The user $user exists on this system."
- elif ls -d /home/$user #如果登录名不存在,检查目录是否存在
- then
- echo "The user $user does not exist on this system."
- echo "However, $user has a directory."
- fi
复制代码 创建自己的重定向
在脚本中重定向输入和输出时,并不局限于这3个默认的文件描述符。在shell中最多可以有9个打开的文件描述符,其他6个从3~8的文件描述符均可用作输入或输出重定向,可以将这些文件描述符中的任意一个分配给文件,然后在脚本中使用它们
创建输出文件描述符
可以用exec命令来给输出分配文件描述符。和标准的文件描述符一样,一旦将另一个文件描述符分配给一个文件,这个重定向就会一直有效,直到重新分配- if command
- then
- command
- elif command
- then
- command
- elif command
- then
- command
- fi
复制代码 重定向文件描述符- if test condition
- #如果没有condition,以非零状态码退出,执行else语句块
- then
- commands
- else
- commands
- fi
- #可以使用test命令确定变量中是否有内容
- if test $variable
- #bash shell提供了另一种条件测试方法,无需声明test命令
- if [ condition ]
- then
- commands
- fi
- #方括号定义测试条件,注意括号内必须有空格
复制代码 创建输入文件描述符
用和重定向输出文件描述符同样的办法重定向输入文件描述符- 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
复制代码 列出打开的文件描述符
lsof命令会列出整个Linux系统打开的所有文件描述符。这是个有争议的功能,因为它会向非系统管理员用户提供Linux系统的信息。鉴于此,许多Linux系统隐藏了该命令,这样用户就不会一不小心就发现
在很多Linux系统中,lsof命令位于/usr/sbin目录。要想以普通用户账户来运行它,必须通过全路径名来引用
具体使用可必应
阻止命令输出
这将脚本作为后台进程运行时很常见
可以将STDERR重定向到一个叫作null文件的特殊文件。null文件跟它的名字很像,文件里什么都没有,shell输出到null文件的任何数据都不会保存
在Linux系统上null文件的标准位置是/dev/nul,重定向到该位置的任何数据都会被丢掉,不会显示- str1 = str2 #检查str1是否和str2相同
- str1 != str2 #检查str1是否和str2不同
- str1 < str2 #检查str1是否比str2小
- str1 > str2 #检查str1是否比str2大
- -n str1 #检查str1的长度是否非0
- -z str1 #检查str1的长度是否为0
复制代码 这是避免出现错误消息,也无需保存它们的一个常用方法
也可以在输入重定向中将/dev/null作为输入文件,通常用它来快速清除现有文件中的数据,而不用先删除文件再重新创建文件testfile仍然存在系统上,但现在它是空文件。这是清除日志文件的一个常用方法,因为日志文件必须时刻准备等待应用程序操作
创建临时文件
Linux专门使用/tmp目录来存放不需要永久保留的文件,大多数Linux发行版配置了系统在启动时自动删除/tmp目录的所有文件
系统上的任何用户账户都有权限在读写/tmp目录中的文件
mktemp命令可以在/tmp目录中创建一个唯一的临时文件。shell会创建这个文件,但不用默认的umask值
它会将文件的读和写权限分配给文件的属主,并将你设成文件的属主。一旦创建了文件,你就在脚本中有了完整的读写权限, 除root外其他人没法访问它
创建本地临时文件
默认情况下,mktemp会在本地目录中创建一个文件。要用mktemp命令在本地目录中创建一 个临时文件,只要指定一个文件名模板即可,模板可以包含任意文本文件名,在文件名末尾加上6个X就行- -d file #检查file是否存在并是一个目录
- -e file #检查file是否存在
- -f file #检查file是否存在并是一个文件
- -r file #检查file是否存在并可读
- -s file #检查file是否存在并非空
- -w file #检查file是否存在并可写
- -x file #检查file是否存在并可执行
- -O file #检查file是否存在并属当前用户所有
- -G file #检查file是否存在并且默认组与当前用户相同
- file1 -nt file2 #检查file1是否比file2新
- file1 -ot file2 #检查file1是否比file2旧
- #比较日期时应先确定文件是否存在
复制代码 mktemp命令会用6个字符码替换这6个X,从而保证文件名在目录中是唯一的
mktemp命令的输出是它所创建的文件的名字。在脚本中使用mktemp命令时,可能要将文件名保存到变量中,这样就能在后面的脚本中引用- val++ #后增
- val-- #后减
- ++val #先增
- --val #先减
- ! #逻辑求反
- ~ #位求反
- ** #幂运算
- << #左位移
- >> #右位移
- & #位布尔和
- | #位布尔或
- && #逻辑和
- || #逻辑或
复制代码 在/tmp目录创建临时文件
-t选项会强制mktemp命令来在系统的临时目录来创建该文件。在用这个特性时,mktemp命令会返回用来创建临时文件的全路径,而不是只有文件名
由于mktemp命令返回了全路径名,因此可以在Linux系统上的任何目录下引用该临时文件,不管临时目录在哪里- ((expression))
- #expression可以是任意的数学赋值或比较表达式
- if (( $val1 ** 2 > 90 ))
- then
- (( val2 = $val1 ** 2 ))
- echo "The square of $val1 is $val2"
- fi
复制代码 创建临时目录
-d选项告诉mktemp命令来创建一个临时目录而不是临时文件- case variable in
- pattern1 | pattern2) commands1;;
- pattern3) commands2;;
- *) default commands;;
- esac
复制代码 在当前目录创建了一个目录,然后用cd命令进入该目录,并创建了两个临时文件,之后这两个临时文件被分配给文件描述符
记录消息
将输出同时发送到显示器和日志文件,不需要输出重定向两次,只要用特殊的tee命令即可
tee命令相当于管道的一个T型接头,它将STDIN过来的数据同时发往两处。一处是STDOUT,另一处是tee命令行所指定的文件名- #!/bin/bash
- case $USER in
- rich | barbara)
- echo "Welcome, $USER"
- echo "Please enjoy your visit";;
- testing)
- echo "Special testing account";;
- jessica)
- echo "Do not forget to log off when you're done";;
- *)
- echo "Sorry, you are not allowed here";;
- esac
复制代码 输出出现在了STDOUT中,同时也写入了指定的文件中,默认情况下,tee命令会在每次使用时覆盖输出文件内容。如果想将数据追加到文件中,必须用-a选项- for var in list
- do
- commands
- done
复制代码 读取.csv格式的数据文件,输出INSERT语句来将数据插入数据库- for test in Alabama Alaska Arizona Arkansas California Colorado
- do
- echo The next state is $test
- done
复制代码 列出等待的作业
atq命令可以查看系统中有哪些作业在等待
作业列表中显示了作业号、系统运行该作业的日期和时间、其所在的作业队列
删除作业
用atrm命令来删除等待中的作业,指定删除作业号即可
安排需要定期执行的脚本
如果需要脚本在每天的同一时间运行或是每周一次、每月一次等,无需多次使用at提交作业,可以使用cron程序来安排要定期执行的作业,cron程序会在后台运行并检查cron表来获知已安排执行的作业
cron时间表采用一种特别的格式来指定作业何时运行- for test in I don\'t know if "this'll" work
- do
- echo word:$test
- done
复制代码 可以使用通配符*来指定条目在任意时候,数值0周日~数值6周六,也可使用取值范围n1-n2,使用,来枚举- #!/bin/bash
- list="Alabama Alaska Arizona Arkansas Colorado"
- list=$list" Connecticut"#向list变量的列表添加了一个值
- for state in $list
- do
- echo "Have you ever visited $state?"
- done
- #输出结果
- Have you ever visited Alabama?
- Have you ever visited Alaska?
- Have you ever visited Arizona?
- Have you ever visited Arkansas?
- Have you ever visited Colorado?
- Have you ever visited Connecticut?
复制代码 如何设置每个月的最后一天执行命令,因为每月的月份不同,常用的方法是加一条使用date命令的if-then语句来检查明天的日期是不是01:- file="states"
- for state in $(cat $file) #从文件读取
- #文件名中没有加入路径。这要求文件和脚本位于同一个目录中。如果不是需要使用全路径名
- do
- echo "Visit beautiful $state"
- done
复制代码 命令列表必须指定要运行的命令或脚本的全路径名,可以像在普通的命令行中那样,添加任何想要的命令行参数和重定向符号- IFS=$'\n':;"
- #将换行符、冒号、分号和双引号作为字段分隔符
复制代码 cron程序会用提交作业的用户账户运行该脚本。因此必须有访问该命令和命令中指定的输出文件的权限
构建cron时间表
每个系统用户包括root用户都可以用自己的cron时间表来运行安排好的任务,Linux提供 了crontab命令来处理cron时间表- for file in /home/rich/test/*
- do
- if [ -d "$file" ]#如果是目录
- then
- echo "$file is a directory"
- elif [ -f "$file" ]#如果是文件
- then
- echo "$file is a file"
- fi
- done
复制代码 默认情况下用户的cron时间表文件并不存在。要为cron时间表添加条目,可以用-e选项
浏览cron目录
如果创建的脚本对精确的执行时间要求不高,用预配置的cron脚本目录会更方便。有4个基本目录:hourly、daily、monthly、weekly
如果脚本需要每天运行一次,只要将脚本复制到daily目录,cron就会每天执行它
anacron程序
cron它假定Linux系统是7×24小时运行的。除非将Linux当成服务器环境来运行,否则此假设未必成立
如果某个作业在cron时间表中安排运行的时间已到,但这时候Linux系统处于关机状态,那么这个作业就不会被运行。当系统开机时,cron程序不会再去运行那些错过的作业
而如果anacron知道某个作业错过了执行时间,它会尽快运行该作业。这意味着如果Linux系统关机了几天,当它再次开机时,原定在关机期间运行的作业会自动运行
这个功能常用于进行常规日志维护的脚本。如果系统在脚本应该运行的时间刚好关机, 日志文件就不会被整理,可能会变很大。通过anacron,至少可以保证系统每次启动时整理日志文件
anacron程序只会处理位于cron目录的程序,比如/etc/cron.monthly,它用时间戳来决定作业是否在正确的计划间隔内运行了,每个cron目录都有个时间戳文件,该文件位于/var/spool/anacron
anacron程序使用自己的时间表(通常位于/etc/anacrontab)来检查作业目录
anacron时间表的基本格式和cron时间表略有不同:- for (( variable assignment ; condition ; iteration process ))
复制代码
- period条目定义作业多久运行一次,以天为单位
- delay条目会指定系统启动后anacron程序需要等待多少分钟再开始运行错过的脚本
- identifier条目是一种特别的非空字符串,如cron-weekly,它用于唯一标识日志消息和错误邮件中的作业
- command条目包含run-parts程序和一个cron脚本目录名,run-parts程序负责运行目录中传给它的任何脚本
anacron不会运行位于/etc/cron.hourly的脚本。这是因为anacron程序不会处理执行时间 需求小于一天的脚本
使用新shell启动脚本
当用户登入bash shell时需要运行的启动文件,基本上依照下列顺序所找到的第一个文件会被运行,其余的文件会被忽略:
- $HOME/.bash_profile
- $HOME/.bash_login
- $HOME/.profile
将需要在登录时运行的脚本放在上面第一个文件中,这样每次启动shell时都会运行该脚本
创建函数
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |