管理整个计算机硬件的其实是操作系统的内核(kernel),这个内核是需要被保护的。所以一般用户就只能通过Shell来跟内核沟通,以让内核完成我们所想要实现的任务。
命令快速编辑按钮
一、Shell的变量功能
变量就是以一组文字或符号等,来替换一些设置或一串保留的数据。
1.1、变量的使用与设置:echo、变量设置规则、unset
变量的使用:echo
变量在被使用时,前面必须要加上美元符号【 $ 】,或是以 $ {variable}的方式来使用。
读取变量: echo $variable | ${variable}
[root@VM_0_8_centos ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo ${HOME}
/root
在bash当中,当一个变量名称尚未被设置时,默认的内容是【空】。变量通过等号(=)进行赋值,且等号两边不能有空格。
[root@VM_0_8_centos ~]# echo ${myname}
[root@VM_0_8_centos ~]# myname=c123
[root@VM_0_8_centos ~]# echo ${myname}
c123
变量的设置规则
- 变量与变量内容以一个等号【=】来连接
myname=c123 - 等号两边不能直接接空格,否则会报错
错误示例:myname = c123 或 myname=c123 456 - 变量名称只能是英文字母与数字,但是开头字符不能是数字
错误示例:1myname=c123 - 变量内容若有空格可使用双引号【"】或单引号【’】将变量内容结合起来
特殊使用情况
-
双引号内的特殊字符如 $ 等,可以保持原本的特性
var=“lang is $LANG” 则 echo $var 输出结果:lang is en_US.utf8 -
单引号内的特殊字符则为一般字符(纯文本)
var=‘lang is $LANG’ 则 echo $var 输出结果:lang is $LANG -
可用转义符【\】将特殊符号(如[Enter]、$、\、空格、’等)变成一般字符
myname=c\ 123 -
在一串命令的执行中,还需要借由其它额外的命令所提供的信息时,可以使用反单引号【` 命令 `】或 【$(命令)】,这些被特殊处理的命令会优先执行
version=“内核的版号:$(uname -r)” 再echo $version 输出结果:内核版本号:3.10.0-1062.18.1.el7.x86_64
-
若该变量为扩增变量内容时,则可用"$ 变量名称" 或 “$ {变量}” 或 $ PATH 累加内容
PATH="$ PATH":/home/bin 或 PATH=$ {PATH}:/home/bin 或 PATH=$ PATH:/home/bin -
若该变量需要在其他子程序运行,则需要以export来使变量变成环境变量
export 自定义变量名称 -
通常大写字符为系统默认变量,自行设置变量可以使用小写字符
-
取消变量的方法为使用unset:【unset 变量名称】 例如取消myname的设置
unset myname
示例:子程序下使用变量
在目前这个shell的情况下,去启用另一个新的shell,新的那个shell就是子程序。
[root@VM_0_8_centos ~]# name=c123
[root@VM_0_8_centos ~]# echo $name
c123
[root@VM_0_8_centos ~]# bash <== 进入子程序
[root@VM_0_8_centos ~]# echo $name <== 子程序中输出name变量的值
<== 子程序没有name这个变量,输出为空
[root@VM_0_8_centos ~]# exit <== 离开子程序
exit
[root@VM_0_8_centos ~]# export name <== 设置name为环境变量
[root@VM_0_8_centos ~]# bash
[root@VM_0_8_centos ~]# echo $name
c123
[root@VM_0_8_centos ~]# exit
exit
[root@VM_0_8_centos ~]# unset name
[root@VM_0_8_centos ~]# echo $name
示例:进入内核模块目录
[root@VM_0_8_centos ~]# cd /lib/modules/$(uname -r)/kernel
[root@VM_0_8_centos kernel]# pwd
/lib/modules/3.10.0-1062.18.1.el7.x86_64/kernel
cd命令进行了两次操作:
1、先进行括号内的操作【uname -r】并得到内核版本 3.10.0-1062.18.1.el7.x86_64
2、将上述的结果带入原命令,故得命令为:cd /lib/modules/3.10.0-1062.18.1.el7.x86_64/kernel
1.2、环境变量的功能
环境变量可以帮我们实现很多功能,包括根目录(主文件夹)的变换、提示字符的显示、执行文件查找的路径等。
用env观察环境变量与常见环境变量说明
[root@VM_0_8_centos ~]# env
XDG_SESSION_ID=18535
HOSTNAME=VM_0_8_centos <== 主机名称
TERM=xterm <== 终端使用的环境类型
SHELL=/bin/bash <== 使用Shell的类型
HISTSIZE=3000 <== 历史命令记录的条数
USER=root <== 使用者的名称
LS_COLORS=rs=0:di=01;34:ln=01;... <== 一些颜色设置
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
PWD=/root <== 目前使用者所在的工作目录(使用pwd获取)
LANG=en_US.utf8 <== 语系
SHLVL=1
HOME=/root <== 使用者的家目录
LOGNAME=root <== 登录者用来登录的账号名称
_=/usr/bin/env <== 上一次使用的命令的最后一个参数(或命令本身)
PATH:执行文件查找路径,目录与目录中间以冒号(:)分隔,由于文件的查找是依序由PATH的变量内的目录来查询的,所以,目录的顺序也是重要的。
用set观察所有变量(含环境变量与自定义变量)
BASH=/bin/bash <== bash的主程序路径
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(2)-release' <== 这两行是bash的版本
COLUMNS=94 <== 在目前终端下,使用的栏位由几个字符长度
HISTFILE=/root/.bash_history <== 历史命令记录的放置文件,隐藏文件
HISTFILESIZE=3000 <== 存起来(与上个变量有关)的文件之命令的最大记录数
HISTSIZE=3000 <== 目前环境下,内存中记录的历史命令最大条数
IFS=$' \t\n' <== 默认的分隔符号
LINES=31 <== 目前的终端下的最大行数
MACHTYPE=x86_64-redhat-linux-gnu <== 安装的机器类型
OSTYPE=linux-gnu <== 操作系统的类型
PS1='[\u@\h \W]\$ ' <== PS1,命令提示符
PS2='> ' <== 如果你使用转义符(\),这是第二行以后的提示字符
$ <== 目前这个shell所使用的PID
? <== 刚刚执行完命令的返回值
$:关于本shell的PID
美元符号本身也是个变量。这个符号同样也代表目前这个shell的进程号,即所谓的PID。通过【echo $$】输出PID号码的值。
[root@VM_0_8_centos ~]# echo $$
6684
?:关于上个执行命令的返回值
这个变量是上一个执行的命令所返回的值,重点是【上一个命令】与【返回值】两个地方。当我们执行某些命令时,这些命令都会返回一个执行后的代码。一般来说,如果成功的执行该命令,则会返回0值;如果执行过程发生错误,就会返回错误的代码,一般就是以非0的数值来替换。
[root@VM_0_8_centos ~]# echo $SHELL
/bin/bash <== 顺利显示变量值,没有错误
[root@VM_0_8_centos ~]# echo $? <== 因为没有错误,所以返回0
0
[root@VM_0_8_centos ~]# 12name=cjw
-bash: 12name=cjw: command not found <== 发生错误
[root@VM_0_8_centos ~]# echo $? <== 返回上一条命令执行错误的代码
127
[root@VM_0_8_centos ~]# echo $? <== 上一条命令执行成功,所有返回0
0
export:自定义变量转成环境变量
自定义变量与环境变量的区别在于【该变量是否会被子进程所继续使用】。子进程仅会继承父进程的环境变量,不会继承父进程的自定义变量。
如果仅执行export而没有接变量时,那么此时将会把所有的环境变量显示出来。
1.3、变量的范围
如果在运行程序的时候,有父进程与子进程的不同进程关系时,则变量可否被引用与export有关,被export后的变量,我们可以称它为环境变量,环境变量可以被子程序所引用,但是其他的自定义变量内容就不会存在于子进程中。
环境变量可被子进程引用的原因:
- 当启动一个shell,操作系统会分配一内存区给shell使用,此内存中的变量可让子进程使用;
- 若在父进程利用export功能,可以让自定义变量的内容写到上述的内存区域当中(环境变量);
- 当加载另一个shell时(即启动子进程,而离开原本的父进程),子shell可以将父shell的环境变量所在的内存区域导入自己的环境变量区域当中。
1.4、变量键盘读取、数组与声明:read、array、declare
read
要读取来自键盘输入的变量,就是用read这个命令。这个命令最常被用在shell脚本的编写当中。
read [-pt] variable
选项与参数:
-p:后面可以接提示符
-t:后面可以接等待的【秒数】
示例
示例一:让使用者由键盘输入一内容,将该内容变成名为atest的变量
[root@VM_0_8_centos ~]# read atest
This is a test
[root@VM_0_8_centos ~]# echo $atest
This is a test
示例二:提示使用者30秒内输入自己的名字,将该输入字符作为名为named的变量内容
[root@VM_0_8_centos ~]# read -p "请输入你的姓名:" -t 30 named
请输入你的姓名:cjw
[root@VM_0_8_centos ~]# echo $named
cjw
declare, typeset
declare 或 typeset 是一样的功能,就是声明变量的类型。如果使用declare后面并没有接任何参数,那么bash就会主动的将所有的变量名称与内容通通显示出来,就好像set一样。
declare [-aixr] variable
选项与参数:
-a:将后面名为variable的变量定义成为数组(array)类型
-i:将后面名为variable的变量定义成为整数(integer)类型
-x:用法与export一样,就是将后面的variable变成环境变量
-r:将变量设置成为readonly类型,该变量不可被更改内容,也不能unset。
示例一:让变量sum进行100+300+50的求和结果
[root@VM_0_8_centos ~]# sum=100+300+50
[root@VM_0_8_centos ~]# echo $sum
100+300+50 <== 定义的变量,默认是字符串格式
[root@VM_0_8_centos ~]# declare -i sum=100+300+50
[root@VM_0_8_centos ~]# echo $sum
450
由于默认情况下,bash对于变量有几个基本的定义
- 变量类型默认为字符串,所以若不指定变量类型,则1+2为一个字符串而不是计算式
- bash环境中的数值计算,默认最多仅能到达整数形态,所以1/3结果是0
示例二:将sum变成环境变量
[root@VM_0_8_centos ~]# declare -x sum
[root@VM_0_8_centos ~]# export | grep sum
declare -ix sum="450"
示例三:让sum变成只读属性,不可修改
[root@VM_0_8_centos ~]# declare -r sum
[root@VM_0_8_centos ~]# sum=testing
-bash: sum: 只读变量
示例四:让sum变成非环境变量的自定义变量
[root@VM_0_8_centos ~]# declare +x sum <== 将-变成+可以进行【取消】操作
[root@VM_0_8_centos ~]# declare -p sum <== -p可以单独列出变量的类型
declare -ir sum="450"
如果你不小心将变量设置为【只读】,通常要注销再登录才能恢复该变量的类型。
数组(array)变量类型
数组的设置方式
var[index]=content
bash提供的是一维数组,var是数组变量名,index表示数组的下标索引,从1开始
[root@VM_0_8_centos ~]# names[1]="xiao ming"
[root@VM_0_8_centos ~]# names[2]="xiao hong"
[root@VM_0_8_centos ~]# names[3]="xiao zhang"
[root@VM_0_8_centos ~]# echo ${names[1]}
xiao ming
[root@VM_0_8_centos ~]# echo "${names[1]}, ${names[2]}, ${names[3]}"
xiao ming, xiao hong, xiao zhang
数组的读取,使用${var[index]}的形式读取。
1.5、与文件系统及程序的限制关系:ulimit
bash可以限制用户的某些系统资源,包括可以开启的文件数量,可以使用的cpu时间,可以使用的内存总量等。
ulimit [-SHacdfltu] [配额]
选项与参数:
-H: hard limit,严格的设置,必定不能超过这个设置的数值。
-S: soft limit,警告的设置,可以超过这个设置值,但是若超过则有警告信息。
在设置上,通常soft会比hard小,举例来说,soft可设置为80而hard设置为100,
那么当可以使用到90(因为没有超过100),但介于80~100之间时,系统会有警告信息通知你。
-a:后面不接任何选项与参数,可列出所有的限制额度。
-c:当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用),
这种文件就被称为内核文件(core file)。此为限制每个内核文件的最大容量。
-f:此shell可以建立的最大文件容量(一般可能设置为2GB)单位为Kbytes。
-d:程序可使用的最大段内存(segment)容量
-l:可用于锁定(lock)的内存量
-t:可使用的最大cpu时间(单位秒)
-u:单一使用者可以使用的最大进程(process)数量
列出目前身份的所有限制数据数值
[root@VM_0_8_centos ~]# ulimit -a
core file size (blocks, -c) 0 <== 只要是0就代表没有限制
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7266
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 100001
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7266
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
限制使用者仅能建立10MBytes以下的容量文件
[root@VM_0_8_centos ~]# ulimit -f 10240
[root@VM_0_8_centos ~]# ulimit -a | grep 'file size'
core file size (blocks, -c) 0
file size (blocks, -f) 10240 <== 最大量为10240Kbytes,相当10Mbytes
[root@VM_0_8_centos ~]# dd if=/dev/zero of=123 bs=1M count=11
文件大小超出限制
1.6、变量内容的删除、取代与替换
变量内容的删除与替换
示例一:让小写的path自定义变量设置的与PATH内容相同
[root@VM_0_8_centos ~]# path=${PATH}
[root@VM_0_8_centos ~]# echo ${path}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
示例二:假设我不喜欢local/bin,所以要将前1个目录删除掉,如何显示?
[root@VM_0_8_centos ~]# echo ${path#/*local/bin:}
/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
示例三:删除前面所有的目录,仅保留最后一个目录
[root@VM_0_8_centos ~]# echo ${path#/*:} <== 由于一个#仅删除掉最短的那个,所以只删除/usr/local/sbin:
/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo ${path##/*:} <== 增加一个#变成##,它变成【删除掉最长的那个数据】
/root/bin
#与##分别代表的含义
- #:符合替换文字的【最短的】那一个
- ##:符合替换文字的【最长的】那一个
#和##都是从前面开始删除内容,%表示从后面开始删除内容
示例四:删除最后那个目录,亦即从:到bin为止的字符
[root@VM_0_8_centos ~]# echo ${path%:*bin} <== 从后开始删除最短的匹配字符
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin
示例五:保留第一个目录
[root@VM_0_8_centos ~]# echo ${path%%:*bin} <== 从后开始删除最长的匹配字符
/usr/local/sbin
示例六:将path的变量内容的sbin替换成大写SBIN
[root@VM_0_8_centos ~]# echo ${path/sbin/SBIN} <== 替换一个符合的内容
/usr/local/SBIN:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo ${path//sbin/SBIN} <== 替换所有符合的内容
/usr/local/SBIN:/usr/local/bin:/usr/SBIN:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
总结说明
变量的测试与内容替换
在某些时刻我们常常需要【判断】某个变量是否存在,若变量存在则使用既有的设置,若变量不存在则给与一个常用的设置。
示例一:测试一下是否存在username这个变量,若不存在则给与username内容为root
[root@VM_0_8_centos ~]# echo ${username}
<== 输出空白,表示username变量不存在
[root@VM_0_8_centos ~]# username=${username-root}
[root@VM_0_8_centos ~]# echo ${username}
root <== 由于username不存在,则被设置为root
[root@VM_0_8_centos ~]# username="cjw test" <== 设置username变量的值
[root@VM_0_8_centos ~]# username=${username-root}
[root@VM_0_8_centos ~]# echo ${username}
cjw test <== username已经设置,输出原来的值
示例二:若username未设置或为空字符,则将username内容设置为root
[root@VM_0_8_centos ~]# username=""
[root@VM_0_8_centos ~]# username=${username-root}
[root@VM_0_8_centos ~]# echo ${username}
[root@VM_0_8_centos ~]# username=${username:-root}
[root@VM_0_8_centos ~]# echo ${username}
root
测试方法总结
二、命令别名与历史命令
2.1、命令别名设置:alias、unalias
命令别名可以简化长命令,还可以增设默认的选项在一些常用的命令上。
示例一:简化ls -al | more 分页查看所有文件详情的命令
[root@VM_0_8_centos ~]# alias lm='ls -al | more'
[root@VM_0_8_centos ~]# type lm
lm 是 'ls -al | more' 的别名
示例二:增设默认的选项在一些常用的命令上
[root@VM_0_8_centos ~]# alias rm='rm -i'
[root@VM_0_8_centos ~]# type rm
rm 是 'rm -i' 的别名
示例三:查看所有命令别名
[root@VM_0_8_centos ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias lm='ls -al | more'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
示例四:删除命令别名
[root@VM_0_8_centos ~]# unalias lm
[root@VM_0_8_centos ~]# lm
-bash: lm: 未找到命令
那么命令别名与变量有什么不同?
命令别名是新创一个新的命令,你可以直接执行该命令,至于变量则需要使用类似【echo】命令才能够调出变量的内容。
三、Bash shell的操作环境
3.1、路径与命令查找顺序
命令的运行顺序
- 以相对/绝对路径执行命令,例如【/bin/ls】 或 【./ls】
- 由alias找到该命令来执行
- 由bash内置的(builtin)命令来执行
- 通过$PATH这个变量的顺序来查找到的第一个命令来执行
查看ls命令的执行顺序
[root@VM_0_8_centos ~]# type -a ls
ls 是 `ls --color=auto' 的别名
ls 是 /usr/bin/ls
3.2、通配符与特殊符号
常用通配符
特殊符号
四、数据流重定向
数据流重定向就是将某个命令执行后应该要出现在屏幕上的数据,给它传输到其它地方,例如文件或是设备。
4.1、什么是数据流重定向
standard output 与 standard error output
标准输出指的是命令执行所返回的正确信息,而标准错误输出可理解为命令执行失败后,所返回的错误信息。
重定向的字符
- 标准输入(stdin):代码为0,使用<或<<
- 标准输出(stdout):代码为1,使用>或>>
- 标准错误输出(stderr):代码为2,使用2>或2>>
示例:将stdout与stderr分别存到不同的文件中,切换到
[root@VM_0_8_centos ~]# find /home -name .bashrc > list_right 2> list_error
/dev/null 垃圾桶黑洞设备与特殊写法
/dev/null 可以吃掉任何导向这个设备的信息
将错误的数据丢弃,屏幕上显示正确的数据
find /home -name .bashrc 2> /dev/null
将命令的数据全部写入名为list的文件中
find /home -name .bashrc > list 2>&1
standard input:< 与 <<
将原本需要由键盘输入的数据,改由文件内容来替换。< 就是标准输入,<< 代表【结束的输入符】
[root@VM_0_8_centos ~]# cat > catfile << "eof"
> This is a test
> Ok or stop
> eof <== 输入关键词,立刻就结束而不需要输入[ctrl]+d
[root@VM_0_8_centos ~]# cat catfile
This is a test
Ok or stop
4.2、$?(命令返回值) 与 $$ 或 ||
由于命令是一个接着一个去执行的,因此,如果真要使用判断,那么这个&&与||的顺序就不能搞错。一般来说,假设判断式有三个, command1 && command2 || command3
顺序通常不会变,而且command2和command3会使用肯定可以执行成功的命令。
五、管道命令(pipe)
管道命令【|】仅能处理经由前面一个命令传来的正确信息,也就是标准输出的信息,对于标准错误并没有直接处理的能力。
在每个管道后面接的第一个数据必定是【命令】,而且这个命令必须要能接受标准输入的数据才行,这样的命令才可以为管道命令。
5.1、选取命令:cut、grep
选取命令,就是将一段数据经过分析后,取出我们想要的,或是经由分析关键词,取得我们所想要的那一行。一般来说,选取信息通常是针对【一行一行】来分析的,并不是整篇信息分析。
cut
将一段信息的某一段给它【切】出来,处理的信息是以【行】为单位的。
cut -d '分隔字符' -f fields <== 用于有特定分隔字符
cut -c '字符区间' <== 用于排列整齐的信息
选项与参数:
-d:后面接分隔字符,与-f一起使用
-f:根据-d的分隔字符将一段信息划分成为数段,用-f取出第几段的意思
-c:以字符(characters)的单位取出固定字符区间
示例一:将PATH变量取出,找出第五个路径
[root@VM_0_8_centos ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo $PATH | cut -d ':' -f 5
/usr/local/python3/bin
[root@VM_0_8_centos ~]# echo $PATH | cut -d ':' -f 3,5 <== 列出第3与第5个路径
/usr/sbin:/usr/local/python3/bin
示例二:将export输出的信息,取得第12个字符以后的所有字符
[root@VM_0_8_centos ~]# export | cut -c 12- <== 12- 代表从第12个字符到最后一个字符的区间
HISTSIZE="3000"
HISTTIMEFORMAT="%F %T "
HOME="/root"
HOSTNAME="VM_0_8_centos"
LANG="zh_CN.utf8"
LESSOPEN="||/usr/bin/lesspipe.sh %s"
LOGNAME="root"
...
示例三:用last将显示的登录者的信息中,仅留下使用者大名
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1
root
root
root
...
cut在处理多空格相连的数据时,可能会比较吃力一点,后面会使用awk来替换。
grep
cut是将一行信息当中,取出某部分我们想要的,而grep则是分析一行信息,若当中有我们所需要的信息,就将该行拿出来。
grep [-acinv] [--color=auto] '查找字符' filename
选项与参数:
-a:将二进制文件以文本文件的方式查找数据
-c:计算找到'查找字符'的次数
-i:忽略大小写的不同,所以大小写相同
-n:输出行号
-v:反向选择,亦即显示出没有'查找字符'内容的那一行
--color=auto:可以将找到的关键字部分加上颜色的显示
示例一:将last当中,有出现root的那一行就显示出来
[ck187420@shell.ceshiren.com ~]$ last | grep 'root'
示例二:与示例一相反,只要没有root的就列出来
[ck187420@shell.ceshiren.com ~]$ last | grep -v 'root'
示例三:在last的输出信息中,只要有root就取出,并且仅取第一栏
[ck187420@shell.ceshiren.com ~]$ last | grep 'root' | cut -d ' ' -f 1
示例四:取出/etc/man_db.conf内含MANPATH的那几行
[ck187420@shell.ceshiren.com ~]$ grep --color=auto 'MANPATH' /etc/man_db.conf
5.2、排序命令:sort、wc、uniq
sort
可以根据不同的数据形式来排序,例如数字与文字的排序就不一样。排序的字符与语系的编码有关,因此,如果需要排序时,建议使用LANG=C来让语系统一。
sort [-fbMnrtuk] [file or stdin]
选项与参数:
-f:忽略大小写的差异,例如A与a视为编码相同
-b:忽略前面的空格字符部分
-M:以月份的名字来排序,例如JAN,DEC等的排序方法
-n:使用【纯数字】进行排序(默认是以文字形式来排序的)
-r:反向排序
-u:就是uniq,相同的数据中,仅出现一行代表
-t:分隔符号,默认是用【Tab】键来分隔
-k:以哪个区间(field)来进行排序的意思
示例一:个人账号都记录在/etc/passwd下,请将账号进行排序
[root@VM_0_8_centos ~]# cat /etc/passwd | sort
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
...
示例二:/etc/passwd是以:分隔的,使用第三栏进行排序
[root@VM_0_8_centos ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
mysql:x:1000:1000::/home/mysql:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@VM_0_8_centos ~]# cat /etc/passwd | sort -t ':' -k 3 -n <== 以数字排列
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
示例三:利用last,将输出的数据仅显示账号,并加以排序
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1 | sort
uniq
将重复的数据仅列出一个显示
uniq [-ic]
选项与参数:
-i:忽略大小写字符的不同
-c:进行计数
示例一:使用last将账号列出,仅取出账号栏,进行排序后仅取出一位
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1 | sort | uniq
reboot
root
wtmp
示例二:列出每个人登录总次数
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1 | sort | uniq -c
2 reboot
131 root
1 wtmp
wc
计算输出信息的整体数据
wc [-lwm]
选项与数据:
-l:仅列出行
-w:仅列出多少字(英文字母)
-m:多少字符
示例一:计算/etc/man_db.conf里面有多少相关行、字数、字符数
[root@VM_0_8_centos etc]# cat /etc/man_db.conf | wc
131 723 5171 <== 分别代表 行、字数、字符数
示例二:取出登录系统的总人数
last 会输出空白行,wtmp、unknown、reboot等无关账号登录信息,需要使用grep过滤
[ck187420@shell.ceshiren.com ~]$ last | grep [a-zA-Z0-9] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' | wc -l
1209
5.3、双向重定向:tee
tee会同时将数据流分送到文件与屏幕(screen),而输出到屏幕的,就是stdout。
tee [-a] file
选项与参数:
-a:以累加(append)的方式,将数据加入file当中
示例一:ls的数据保存到~/homefile,同时屏幕也有输出信息
[root@VM_0_8_centos ~]# ls -l /home | tee homefile | more
总用量 2113032
-rw-r--r-- 1 root root 127431820 7月 31 2020 jdk-8u261-linux-x64.rpm
-rw-r--r-- 1 root root 66244250 7月 31 2020 jenkins-2.235.3-1.1.noarch.rpm
drwx------ 2 mysql mysql 4096 12月 30 17:13 mysql
...
示例二:查看根目录的信息,并把数据累加到homefile文件中
[root@VM_0_8_centos ~]# ls -l / | tee -a homefile | more
总用量 80
lrwxrwxrwx. 1 root root 7 3月 7 2019 bin -> usr/bin
drwxr-xr-x 2 root root 4096 5月 26 15:23 bitnami
dr-xr-xr-x. 5 root root 4096 5月 22 10:24 boot
...
5.4、字符转换命令:tr、col、join、paste、expand
tr
tr 可以用来删除一段信息当中的文字,或是进行文字信息的替换。
tr [-ds] SET1 ...
选项与参数:
-d:删除信息当中的SET1这个字符
-s:替换掉重复的字符
示例一:将last输出信息中,所有小写变成大写字符
[root@VM_0_8_centos ~]# last | tr '[a-z]' '[A-Z]' <== '[a-z]'外面的单引号可以去除,同样可以执行
...
ROOT PTS/0 117.147.40.136 SUN JUL 12 12:42 - 14:03 (01:21)
REBOOT SYSTEM BOOT 3.10.0-1062.18.1 SUN JUL 12 12:40 - 11:22 (328+22:41)
示例二:将/etc/passwd输出信息中,将冒号(:)去除
[root@VM_0_8_centos ~]# cat /etc/passwd | tr -d ':'
rootx00root/root/bin/bash
binx11bin/bin/sbin/nologin
...
col
col [-x]
选项与参数:
-x:将tab键转换成对等的空格键
示例:利用cat -A 显示出所有特殊键,最后以col将[tab]转成空白
[root@VM_0_8_centos ~]# cat -A /etc/man_db.conf <== ^I就是tab
[root@VM_0_8_centos ~]# cat /etc/man_db.conf | col -x | cat -A | more
...
MANPATH_MAP /bin /usr/share/man$
MANPATH_MAP /usr/bin /usr/share/man$
MANPATH_MAP /sbin /usr/share/man$
...
join
join(加入/参加)用于处理两个文件之间的数据,主要是处理【两个文件当中,有相同数据的那一行,才将它加在一起】。
join [-ti12] file1 file2
选项与参数:
-t: 默认以空格字符分隔数据,并且比对【第一个栏位】的数据,如果两个文件相同,则将两条数据连成一行,且第一个栏位放在第一个
-i:忽略大小写的差异
-1:这个是数字1,代表【第一个文件要用哪个栏位来分析】的意思
-2:代表【第二个文件要用哪个栏位来分析】的意思
示例一:用root的身份,将/etc/passwd与/etc/shadow相关数据整合成一栏
[root@VM_0_8_centos ~]# head -n 3 /etc/passwd /etc/shadow
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
==> /etc/shadow <==
root:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::
bin:*:17834:0:99999:7:::
daemon:*:17834:0:99999:7:::
由输出的数据可以发现这两个文件的最左边栏位都是相同账号,且以:分隔
[root@VM_0_8_centos ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:17834:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:17834:0:99999:7:::
第二个文件的相同栏位并不会显示,因为已经在最左边的栏位出现了
示例二:/etc/passwd第四个栏位是GID,这个GID记录在/etc/group当中的第三个栏位,整合这两个文件
[root@VM_0_8_centos ~]# head -n 3 /etc/passwd /etc/group
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
==> /etc/group <==
root:x:0:
bin:x:1:
daemon:x:2:
[root@VM_0_8_centos ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:
此外,需要特别注意的是,在使用join之前,你所需要处理的文件应该要事先经过排序(sort)处理,否则有些比对项目就会被忽略。
paste
作用:直接将两行贴在一起,且中间以[Tab]键隔开
paste [-d] file1 file2
选项与参数:
-d:后面可以接分隔字符,默认是以[Tab]来分隔
-:如果file部分写成-,表示来自标准输入的数据的意思
示例一:用root身份,将/etc/passwd与/etc/shadow同一行贴在一起
[root@VM_0_8_centos ~]# paste /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash root:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin bin:*:17834:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:17834:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin adm:*:17834:0:99999:7:::
...
示例二:先将/etc/group读出,然后与示例一贴在一起,且仅取出前三行
[root@VM_0_8_centos ~]# cat /etc/group | paste /etc/passwd /etc/shadow -| head -n 3
root:x:0:0:root:/root:/bin/bash root:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7::: root:x:0:
bin:x:1:1:bin:/bin:/sbin/nologin bin:*:17834:0:99999:7::: bin:x:1:
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:17834:0:99999:7::: daemon:x:2:
expand
作用:将[Tab]按键转成空格键
expand [-t] file
选项与参数:
-t:后面可以接数字,一般来说一个Tab按键可以用8个空格键替换,我们也可以自定义一个[Tab]按键代表多少个字符
示例一:将/etc/man_db.conf内行首为MANPATH的字样就取出,仅取前三行
[root@VM_0_8_centos ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 <== ^行首标志
MANPATH_MAP /bin /usr/share/man
MANPATH_MAP /usr/bin /usr/share/man
MANPATH_MAP /sbin /usr/share/man
示例二:承上,列出所有符号
[root@VM_0_8_centos ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | cat -A
MANPATH_MAP^I/bin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/bin^I^I/usr/share/man$ <== [Tab]键显示成^I
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$
示例三:承上,将[Tab]按键设置成6个字符
[root@VM_0_8_centos ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 6 - | cat -A
MANPATH_MAP /bin /usr/share/man$
MANPATH_MAP /usr/bin /usr/share/man$
MANPATH_MAP /sbin /usr/share/man$
5.5、划分命令:split
split 可以帮助将一个大文件,依据文件大小或行数来划分,就可以将大文件划分成为小文件了。
split [-bl] file PERFIX
选项与参数:
-b:后面可接欲划分成的文件大小,可加单位,例如b、k、m等
-l:以行数来进行划分
PERFIX: 代表前缀字符的意思,可作为划分文件的前缀文字
示例一:将/etc/services拆分成300k一个文件
[root@VM_0_8_centos ~]# split -b 300k /etc/services services
[root@VM_0_8_centos ~]# ll -h services*
-rw-r--r-- 1 root root 300K 6月 6 19:33 servicesaa
-rw-r--r-- 1 root root 300K 6月 6 19:33 servicesab
-rw-r--r-- 1 root root 55K 6月 6 19:33 servicesac
示例二:将拆分出来的三个小文件合成一个文件,名称为servicesback
[root@VM_0_8_centos ~]# cat services* >> servicesback
[root@VM_0_8_centos ~]# ll -h servicesback
-rw-r--r-- 1 root root 655K 6月 6 19:37 servicesback
示例三:使用 ls -al / 输出的信息中,每十行记录成一个文件
[root@VM_0_8_centos ~]# ls -al / | split -l 10 - lsroot
[root@VM_0_8_centos ~]# wc -l lsroot*
10 lsrootaa
10 lsrootab
6 lsrootac
26 总用量
5.6、参数代换:xargs
xargs 用于产生某个命令的参数的意思。xargs 可以读入stdin 的数据,并且以空格符或换行符作为标识符,将stdin的数据分隔成为参数。因为是以空格符作为分隔,所以,如果有一些文件名或其他意义的名词内含有空格符的时候,xargs可能就会误判了。
xargs [-0epn] command
选项与参数:
-0:如果输入的stdin含有特殊字符,例如`、\、空格等字符,这个-0参数可以将它还原成一般字符,这个参数可以用于特殊状态。
-e:这是EOF(end of line),后面可以接一个字符,当xargs分析到这个字符时,就会停止工作
-p:在执行每个命令时,都会询问使用者的意思
-n:后面接次数,每次command命令执行时,要使用几个参数的意思
当xargs后面没有接任何的命令时,默认是以echo来进行输出
示例一:将/etc/passwd内的第一栏取出,仅取出三行,使用id这个命令将每个账号内容显示来
[root@VM_0_8_centos ~]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
uid=0(root) gid=0(root) 组=0(root)
uid=1(bin) gid=1(bin) 组=1(bin)
uid=2(daemon) gid=2(daemon) 组=2(daemon)
示例二:每次执行id时,都要询问使用者是否操作
[root@VM_0_8_centos ~]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id
id root ?...y
uid=0(root) gid=0(root) 组=0(root)
id bin ?...y
uid=1(bin) gid=1(bin) 组=1(bin)
id daemon ?...y
uid=2(daemon) gid=2(daemon) 组=2(daemon)
示例三:将所有的/etc/passwd内的账号都以id查看,但查到sync就结束命令串
需要注意的是,-e'sync'是连在一起
[root@VM_0_8_centos ~]# cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -n 1 id
uid=0(root) gid=0(root) 组=0(root)
uid=1(bin) gid=1(bin) 组=1(bin)
uid=2(daemon) gid=2(daemon) 组=2(daemon)
uid=3(adm) gid=4(adm) 组=4(adm)
uid=4(lp) gid=7(lp) 组=7(lp)
要使用xargs的原因是,很多命令其实并不支持管道命令,因此可以通过xargs来提供该命令使用标准输入
示例四:找出/usr/sbin 下面具有特殊权限的文件名,并使用ls -l 列出详细属性
[root@VM_0_8_centos ~]# find /usr/sbin -perm /7000 | xargs ls -l
-rwxr-sr-x 1 root root 11224 8月 9 2019 /usr/sbin/netreport
-rwsr-xr-x. 1 root root 11216 4月 11 2018 /usr/sbin/pam_timestamp_check
-rwxr-sr-x. 1 root postdrop 218632 10月 31 2018 /usr/sbin/postdrop
...
5.7、关于减号【 - 】的用途
在管道命令当中,常常会使用到前一个命令的stdout作为这次的stdin,某些命令需要用到文件名(例如tar)来进行处理时,该stdin与stdout可以利用减号’-'来替代。
[root@VM_0_8_centos homeback]# mkdir /tmp/homeback
[root@VM_0_8_centos homeback]# tar -cvf - /home | tar -xvf - -C /tmp/homeback
鸟哥的私房菜