文本的主要内容为,bash特性说明,bash编程基础,包括变量,逻辑与算术运算,脚本的编写执行;
正则表达式,grep,vim,文本与文件过滤命令,以及特殊权限与FACL
一、Bash
1. 命令hash
我们之前有介绍,之所以用户能够在执行命令时不输入全部的路径1,是因为bash会根据一个叫做PATH的环境变量中提供的字符串去对应的路径下搜索可执行程序。其值一般为:
[root@localhost ~]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
这个搜索过程显然需要花费时间,为了节省这个时间,bash会将执行过的程序的路径保存在内存中的特定位置,下次再次执行时可直接从该位置搜索,若搜索到则直接使用,不必再去文件系统中查找。而由于保存的内容是使用散列存储,其在查找时的时间复杂度为 O ( 1 ) O(1) O(1),效率极高。
该存储方式又叫做哈希(hash),故相应命令被称为hash
hash
该命令是bash的内建(builtin)命令,可管理bash此前生成的哈希表。该命令用法较为简单。
-
查看命令哈希的结果:
-
[root@localhost ~]# hash hits command 1 /usr/bin/startx 1 /usr/bin/tail 14 /usr/bin/vim 1 /usr/bin/expr
- 缓存的结果是以键值对(Key-Value)的形式显示,hits表示命中次数,command表示命令路径,其基名就是我们执行的命令。 清空哈希表
-
[root@localhost ~]# hash -r
清空指定条目
-
[root@localhost ~]# hash -d COMMAND
2. Bash配置文件
在介绍配置文件之前, 先介绍一款文本编辑器,以作编辑之用。
nano
nano是一款轻量级的文本编辑器,相当于Windows上的notepad(记事本),可以直接通过nano后跟文件名的方式使用,若文件名不存在,则将会新建该文件(若选择保存),其打开界面如下:
这是一个全屏编辑器,上方显示了软件版本以及当前文件,下方为相关操作,如Ctrl+X为退出等。
bash配置文件
Bash作为最常用的shell程序之一,他的配置文件有多个,我们一般将其分为两类:
bash配置文件
- profile类:为交互式登录的shell进程提供配置
- /etc/profile
- /etc/profile.d/*.sh
- ~/.bash_profile
- bashrc类:为非交互式登录的shell进程提供配置
- /etc/bashrc
- ~/.bashrc
虽然我们一般习惯如此去说明,事实上不论是登录还是非登录shell,在运行时都会读取这两类文件。
由于我们在命令行中的配置虽然可以立即生效,但是作用域仅为当前进程,而若要其永久有效,就需要将配置写入配置文件中。
另外,由其位置可知,/etc/中的配置对所有用户有效,而用户家目录中的配置仅对当前用户生效。
先回顾一下登录式shell与非登录式shell
- 登录式Shell:正常通过某终端登录、su -[l] USERNAME进行的用户切换
- 非登录式Shell:图形终端下打开的命令窗口(伪终端)、自动执行的shell脚本、su USERNAME执行的登录切换
-
两类文件的一般功能
-
-
profile类文件
- 设定环境变量
- 运行命令或脚本
-
-
bashrc类文件
- 设定本地变量
- 定义命令别名
如,root/.bashrc内容为:
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
该文件定义了命令别名,而后读取/etc/bashrc文件2。
对于登录式shell与非登录式shell,他们读取配置文件的顺序不同:
- 登录式shell
- 非登录式shell
-
使用示例
-
- 添加用户别名,cls=clear,当前用户作用范围,使其在每次登陆都有效
在其后添加一行:[root@localhost ~]# nano .bashrc
alias cls = 'clear'
- 添加用户别名,cls=clear,当前用户作用范围,使其在每次登陆都有效
-
- 使用户在登陆系统时显示当前时间,只对当前用户生效
在其后添加一行:[root@localhost ~]# nano .bash_profile
echo "Hello,Welcome to our system.It is `date`."
- 使用户在登陆系统时显示当前时间,只对当前用户生效
修改了配置文件后,将在下次启动新的shell进程时生效,若要立即生效,可通过source命令通知bash重新读取。
source
该命令用于通知当前shell读取或执行给定的配置文件,其后直接跟配置文件即可,如:
[root@localhost ~]# source .bashrc
另外,source可以简写为.(点号),以下命令与上方命令等价:
[root@localhost ~]# . .bashrc
二、Bash编程
1. 变量
变量(Variable) 相信大家并不陌生,其实质上就是一段命名的内存空间。而在bash中,同样支持变量的概念。
bash中的变量类型
变量类型 | 说明 |
---|---|
环境变量 | 作用域为当前shell进程及其子进程 |
本地变量 | 作用域为整个bash进程 |
局部变量 | 作用域为当前代码段(通常指函数) |
位置变量 | $1,$2,…用于让脚本在脚本代码中调用通过命令行传递给它的参数 |
特殊变量 | 保存某些特殊数据3 |
-
特殊变量
- $0: 脚本名称本身
-
$?: 上一条命令的执行状态
- 状态用数字表示:0-255
- 成功:0
- 失败:1-255
- $$:脚本运行的当前进程ID
- $!:Shell最后运行的后台进程的PID
- $#: 参数数量
- $*: 所有参数的一个字符串
- $@:所有参数单独作为每个字符串
- $1、$2…:位置变量,对应第一、第二个参数
-
关于$@与$*的区别:
- 只有在双引号中体现出来。假设在脚本运行时写了三个参数(分别存储在$1 $2 $3)则"$*" 等价于 “$1 $2 $3"(传递了一个参数);而“$@" 等价于 “$1” “$2” “$3”(传递了三个参数)
变量声明
bash中变量的命名规则同其他语言类似,变量名只能包含数字、字母和下划线,而且不能以数字开头,另外,变量赋值时不能使用$。
本地变量的声明
bash为弱类型,故在声明变量时不必指定变量类型(但这不代表这些变量没有类型),可直接使用如下形式声明变量:
[set] VARNAME=VALUE
set可省略
使用不带参数的set命令可查看系统已定义的所有变量
只读变量的声明
readonly VARNAME
或
declare -r VARNAME
在声明时指定readonly,或使用declare -r,可声明只读变量(常量),由于其在声明后不可更改内容,需要在声明时进行初始化。
环境变量的声明
export VARNAME=VALUE
或
VARNAME=VALUE; export VARNAME
或
VARNAME=VALUE; declare -x VARNAME
或
declare -x VARNAME=VALUE
-
Tips;
- 在同一行执行的多条命令中间可使用;(分号)隔开 环境变量的查看
- printenv
- env
- export
- declare -x
环境变量对当前shell及其子shell都有效
局部变量的声明
local VARNAME=VALUE
仅对局部代码生效
变量的引用
- ${VARNAME} 不会引起混淆的话,{}可省略
- “” 弱引用,其中的变量引用会被替换为变量值
- ‘’ 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
2. 逻辑运算
与(AND)
“与”表示“并且”之意,即两种事件都发生,使用 && 表示,其运算结果为
- 1 && 1 = 1
- 1 && 0 = 0
- 0 && 1 = 0
- 0 && 0 = 0
即二者都为真(True),结果才为真(False),否则为假
或(OR)
“或”表示二者任一即可,使用 || 表示,其运算结果为
- 1 || 1 = 1
- 1 || 0 = 1
- 0 || 1 = 1
- 0 || 0 = 0
即二者都为假,结果才为假,否则为真
非(NOT)
“非”表示“不”,取相反结果之意,这是一个单目运算符,使用 ! 其运算结果为
- ! 1 = 0
- ! 0 = 1
逻辑短路
概念
由于“与”和“或”运算时自左而右的,加之其运算特性,我们可以得出如下结论
- 若且(AND)运算的第一个运算数(Operand)为假,结果一定为假;
- 若或(OR)运算的第一个运算数为真,结果一定为真;
如此则不必再去计算其二个运算数(或表达式)的结果,可直接得出最终结果,这种运算方式成为短路运算,也叫作逻辑短路。
应用
通过这种特性,在bash中可是实现类似if条件判断的处理。
我们知道,程序在执行完后会返回一个执行状态,用于标识程序执行成功与否,使用0标识执行成功(即“真”),非0则标识执行失败(即“假”)
可通过判断该状态返回值,对不同的结果(成功或失败)处以不同的操作,如
查看user1是否存在,若存在,则输出其信息,否则创建之:
id user1 2> /dev/null || useradd user1
可以组合多个这样的命令以实现更复杂的控制
德摩根定律
该定律y应用很广泛,此处也将其列出
A
⋂
B
‾
≡
A
‾
⋃
B
‾
\overline{A \bigcap B} \equiv \overline{A} \bigcup \overline{B}
A⋂B≡A⋃B
A ⋃ B ‾ ≡ A ‾ ⋂ B ‾ \overline{A \bigcup B} \equiv \overline{A} \bigcap \overline{B} A⋃B≡A⋂B
3. 算术运算
由于bash是弱类型的语言,其声明的变量默认为字符,运算法则默认也是按照字符运算进行的,若要使其进程算术运算,可使用如下几种方式:
- let VAR = ARITH_EXPR
- VAR = $[ARITH_EXPR]
- VAR = $((ARITH_EXPR))
- VAR = $(expr ARITH_EXPR)
若欲计算变量A与变量B的和,以上表示的实现为:
#let VAR = ARITH_EXPR
let C = $A + $B
#VAR = $[ARITH_EXPR]
C = $[$A + $B]
#VAR = $((ARITH_EXPR))
C = $(($A + $B))
#VAR = $(ARITH_EXPR)
C = $(expr $A + $B)
C = `expr $A + $B`
如,计算user1,user2,user3用户的UID之和
#!/bin/bash
uid1=`id -u user1`
uid2=`id -u user2`
uid3=`id -u user3`
uid_sum=$[$uid1 + $uid2 + $uid3]
echo "The sum of uid if $uid_sum."
4. 运行脚本
同其他编程不同,所谓的bash编程,调用的是系统上已有的程序命令,通过bash内置的变量、流程控制等机制实现的。
-
程序的执行方式
-
-
-
编译执行
- 由源代码直接一次性编译为而进行文件,可直接执行
-
-
-
-
解释执行
- 程序文件内核无法直接理解,需要外部程序解释源文件,逐条执行
-
代码的源文件问文本格式,而内核只能执行二进制格式文件,故直接执行该文件内核是无法理解的,而bash是解释执行的,需要为其程序文件执行一个解释器。
在程序文件内容的最开始处使用以 #! 开头,后跟解释器程序路径的字符串来通知内核,使用该程序对文件进行解释执行,而不是直接执行,这个字符串被称为 Shebang 。上文程序的第一行就是Shebang。
若不指定,则脚本无法直接执行,但可以明确指定解释器,将该脚本文件当做参数让解释器执行,如上面的文件为:
uid1=`id -u user1`
uid2=`id -u user2`
uid3=`id -u user3`
uid_sum=$[$uid1 + $uid2 + $uid3]
echo "The sum of uid if $uid_sum."
可使用bash SCRIPT_NAME
执行之
另外,默认新建的文件是没有执行权限的,若要直接执行,则需要为其赋予执行权限:
chmod +x /PATH/TO/SCRPTE
三、正则表达式
0. 概念
正则表达式(REGular EXPression,REGEXP)使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串的机制。它将一些字符作为元字符(Meta Characteristic) 用于标识一类字符或用于特殊限定,而不是标识其原有的字面意义。
在进行文本匹配时,我们所写的匹配表达式被称为模式(Pattern) ,而在Linux中,最常用的支持正则表达式的程序为grep家族程序,根据其划分,又分为:
- BRE(Basic RegEx),基本正则表达式
- ERE(Extended RegEx),扩展正则表达式
在介绍正则表达式之前,前介绍grep的用法
1. grep、egrep、fgrep
这三个命令类似,都用作文本过滤,grep(Global Search Regular EXpression and print out the line)默认使用BRE,egrep默认使用ERE,fgrep模式不支持REGEXP,f为fast之意。
由于以上三个命令可以使用参数而达到与彼此相同的效果,故而此处以grep为例进行说明,其用法如下:
grep [OPTIONS] PATTERN [FILE...]
[OPTIONS]
-i ignore-case 忽略大小写
--colour=auto
将匹配到的字符高亮显示,默认命令别名开启
-v 反向匹配,显示没有被模式匹配到的行
-o 只显示被模式匹配到的字符串,而非整行
-q 静默模式,不输出任何信息
-E 支持扩展的正则表达式(egrep)
-F 支持快速匹配(fgrep)
-A # After,显示被模式匹配到的后面的#行
-B # Before,显示被模式匹配到的前面的#行
-C # Context,显示被模式匹配到的前#行与后#行
-P 使用perl风格的正则表达式
PATTERN
模式,即用于匹配的条件,将在下面介绍
2. 基本正则表达式(BRE)
Globbing回顾
通配符 | 意义 |
---|---|
* | 任意长度的任意字符 |
? | 任意单个字符 |
[] | 指定范围内的任意单个字符 |
[^] | 指定范围外的任意单个字符 |
BRE元字符
正则表达式的介绍主要内容为介绍其元字符,分为以下几类:
- 字符匹配
- 次数匹配
- 位置锚定
- 分组
字符匹配
元字符 | 意义 |
---|---|
. | 匹配任意字符 |
[] | 匹配指定范围内的字符 |
[^] | 匹配指定范围外的字符 |
注意,这里只是确定匹配什么字符,匹配次数并不由此限制。
关于范围,可使用如下方式表示:
范围 | 意义 |
---|---|
[0-9],[[:digit:] | 数字 |
[a-z],[[:lower:]] | 小写字母 |
[A-Z],[[:upper:]] | 大写字母 |
[[:punct:]] | 标点符号 |
[[:space:]] | 空白符号 |
[[:alpha:]] | 所有字母(大写与小写) |
[[:alnum:]] | 字母与数字 |
以上两个中括号的意义为,外层标识正则表达式的范围,内层与其中的内容共同标识一个集合,若要匹配外围以外的,组在两个中括号之间加上^即可,如:
[^[:lower:]]
:非小写字母
匹配次数
用在要指定其出现的次数的字符的后面,用于限定其前面字符出现的次数
元字符 | 意义 |
---|---|
* | 匹配其前面字符任意次(0次,1次,或多次) |
\? | 0次或1次 |
\+ | 1次或多次 |
\{m\} | m次 |
\{m,n\} | 至少m次,至多n次 |
这里需要使用转义,因为BRE将+、?、{、}等字符默认是作为字字面意义进行匹配的,这里需要使其作为元字符使用。
另外,关于次数匹配也有以下用法:
次数表示 | 意义 |
---|---|
.* | 任意长度的任意字符 |
\{0,n\} | 至多n次 |
\{m,\} | 至少m次 |
贪婪模式
试想若有如下内容的文本:
one two one three one
使用以下命令进行匹配:
grep -o "one.*one" test.grep
得到的结果为:
one two one three one
而事实上“one two one”也是满足模式的,这里之所以是如此结果,是因为grep默认工作在 贪婪模式 下,这意味着grep会尽可能长地匹配字符。
若要尽可能短地匹配,则需要其在非贪婪模式下匹配,而grep与egrep默认是不支持这种模式的。
我们可以使用-P选项,以为使用Perl语言风格的正则表达式进行模式匹配,号称Perl的正则表达式引擎是非常强大的。
Perl风格中,在次数限定元字符后加 ? 可使其工作在非贪婪模式下,如:
grep -o -P "one.*?one" test.grep
结果为
one two one
位置锚定
元字符 | 意义 |
---|---|
^ | 锚定行首 |
$ | 锚定行尾 |
\<或\b | 锚定词首,用于单词左侧 |
\>或\b | 锚定词尾,用于单词右侧 |
常见用法
模式 | 意义 |
---|---|
\<PATTERN\> | 匹配完整单词 |
^PATTERN$ | 用PATTERN匹配整行 |
^$ | 空白行 |
^[[:space:]]*$ | 空行或包含空白字符的行 |
分组与引用
有时需要将一个组合作为一个单位进行限定,如要匹配出现多个连续的“ab”,此时可使用分组
分组是使用小括号实现的,不过在BRE中需要转义,如以上要求的模式应写为\(ab\)*
分组的另一个作用为,可再次引用匹配到的内容(后向引用),如若使用r..t
匹配到了“root”,则在下次引用时,引用的占位符将被替换为“root”。
分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部变量中,这些变量的命名方式为\1,\2,\3,……
如,有以下文本内容:
He likes his lover.
She loves her liker.
He loves his lover.
She likes her liker.
grep '\(l..e\).*\1r'
将会匹配到:
He loves his lover.
She likes her liker.
例
- 显示/proc/meminfo文件中以不区分大小的s开头的行;
grep -i '^s' /proc/meminfo grep '^[sS]' /proc/meminfo
- 显示/etc/passwd中以nologin结尾的行;
grep 'nologin$' /etc/passwd
- 取出默认shell为/sbin/nologin的用户列表
grep "nologin$' /etc/passwd | cut -d: -f1
- 取出默认shell为bash,且其用户ID号最小的用户的用户名
grep 'bash$' /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1
- 显示/etc/inittab中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行;
grep "^#[[:space:]]\{1,\}[^[:space:]]" /etc/inittab
- 显示/etc/inittab中包含了:一个数字:(即两个冒号中间一个数字)的行;
grep ':[0-9]:' /etc/inittab
- 显示/boot/grub/grub.conf文件中以一个或多个空白字符开头的行;
grep '^[[:space:]]\{1,\}' /boot/grub/grub.conf
- 显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;
grep '^\([0-9]\).*\1$' /etc/inittab
- 找出"netstat -tan"命令的结果中以’LISTEN’后跟0、1或多个空白字符结尾的行;
netstat -tan | grep "LISTEN[[:space:]]*$"
3. 扩展正则表达式(ERE)
ERE与BRE类似,只是将更多的字符纳入了元字符,如此在使用时将不必转义,其他与BRE类似,与这里做如下总结
字符匹配
元字符 | 意义 |
---|---|
. | 匹配任意字符 |
[] | 匹配指定范围内的字符 |
[^] | 匹配指定范围外的字符 |
匹配次数
元字符 | 意义 |
---|---|
* | 匹配其前面字符任意次(0次,1次,或多次) |
? | 0次或1次 |
+ | 1次或多次 |
{m} | m次 |
{m,n} | 至少m次,至多n次 |
位置锚定
元字符 | 意义 |
---|---|
^ | 锚定行首 |
$ | 锚定行尾 |
\<或\b | 锚定词首,用于单词左侧 |
\>或\b | 锚定词尾,用于单词右侧 |
分组与引用
元字符 | 意义 |
---|---|
() | 分组 |
\1, \2, \3, … | 后向引用 |
或者
元字符 | 意义 |
---|---|
| | 表示“或者”之意 |
该元字符在BRE中并未出现,这里需要说明的是,|匹配的是真个左边或整个右边,而不是单个字符,如:
c|Cat
可以匹配的是c与Cat,而非cat与Cat,若要用C|cat
表示C|c
可以使用()
分组:(C|c)at
四、文本处理命令
wc
wc以为Word Count,用于文本统计,用法如下:
wc [OPTION]... [FILE]...
[OPTION]
-l print the newline counts
-L print the length of the longest line
-w print the word counts
-c print the byte counts
-m print the character counts
该命令只影响输出,不修改源文件
cut
cut顾名思义,可用于文本分割,用法为:
cut OPTION... [FILE]...
OPTION
-d 指定字段分隔符,选项与分隔符之间可以没有空格,默认分隔符是空格
-f# 指定要显示的字段,后跟数字,可以没有空格,例:
-f1 显示第一个
-f1,3 显示第一个和三个
-f1-3 显示第一个到第三个
--output-delimiter=STRING
指定输出时的分隔符,默认与输入时的相同
该命令只影响输出,不修改源文件
sort
sort以为排序,用法为:
sort [OPTION]... [FILE]...
[OPTION]
-n 按照数值(的大小)排序
-r, --reverse 逆序
-t 指定分隔符
-k 以哪个字段为关键字进行排序
-u 排序后相同的行只显示一次
-f 排序时忽略字符大小写
该命令只影响输出,不修改源文件
uniq
该命令用于报告或移除重复的行,用法为:
uniq [OPTION]... [INPUT [OUTPUT]]
[OPTION]
-c:显示每行的重复次数
-u:仅显示未曾重复过的行
-d:仅显示重复过的的行
需要说明的是,只有内容相同且位置相邻,才被文人是相同的行
diff
diff意为difference,用于逐行对比文件的不同,用法为:
diff [OPTION]... FILES
[OPTION]
-u:使用unified机制,即显示要修改的上下文,默认为3行
可以使用输出重定向,将生成的补丁文件保存:
diff /PATH/TO/OLDFILE /PATH/TO/NEWFILE > /PATH/TO/PATCH_FILE
patch
patch意为补丁,是用于向原始文件打补丁的工具,用法为:
patch [OPTIONS] -i /PATH/TO/PATCH_FILE /PATH/TO/OLDFILE
patch /PATH/TO/OLDFILE < /PATH/TO/PATCH_FILE
五、文件查找
locate
locate意为位置,该命令将基于已经建立的文件索引进行搜索,速度较快,但是非实时,使用方式为:
locate [OPTION]... PATTERN...
[OPTION]
-b:只匹配基名
-c:统计出共有多少个符合条件的文件
-r:基于BRE搜索
另外,可以使用updatedb
命令来手动生成文件索引数据库,注意,该操作将会遍历整个根文件系统,对资源占用较大
find
与locate不同的是,find命令是实时查找,支持多种搜索方式,但是速度较慢,用法为:
find [PATH] [CONDITION] [ACTION]
[PATH] 搜索路径,默认为当前目录
[CONDITION] 搜索条件,可以是文件名、大小、类型、权限等标准,默认为指定路径下的所有文件,即无条件
-name 'FILENAME' 对文件名做精确匹配,区分大小写
文件名通配
* 任意长度的任意字符
? 任意单个字符
[] 指定范围内的
[^] 指定范围外的
-iname 'FILENAME' 文件名匹配不区分大小写
-regex 'PATTERN' 基于正则表达式进行文件名匹配
以PATTERN匹配整个文件路径字符串,而不仅仅是文件名
-user USERNAME 根据属主查找
-group GRPNAME 根据属组查找
-uid UID 根据UID查找
-gid GID 根据GID查找
若一个文件的属主用户被删除,则该文件的属主将变为删除用户的UID,此时,该文件没有属主,属组亦然
-nouser 查找没有属主的文件
-nogroup 查找没有属组的文件
-type TYPE 根据文件类型查找
f 普通文件
d 目录
c 字符设备文件
b 块设备文件
l 符号链接文件
p 命名管道
s 套接字文件
-size [+|-]
指定查找大小,后跟数字和单位,若没给出单位,则为默认的“字节”,+和-表示至少、至多,可使用其他单位,如
#k
#M
#G
指定大小查找时,若没有指定+或-,会匹配在给定大小为1单位一内的所有文件
即:
#:(#-1, #]
-#: [0, #-1]
+#: (#, ∞)
根据文件的时间戳查找
以天为单位(time)
-mtime[+|-]# 修改时间/天
-ctime [+|-]# 改变时间/天
-atime [+|-]# 访问时间/天
以分钟为单位(min)
-mmin [+|-]# 修改时间/分钟
-cmin [+|-]# 改变时间/分钟
-amin [+|-]# 访问时间/分钟
+#:[#+1, ∞)
-#:[0, #)
#:[#, #+1)
根据文件的权限查找
-permMODE:精确匹配
/MODE: 任何一类用户(u,g,o)的任何一位(r,w,x)权限匹配
9位权限位
常用于查找某类用户的特定权限是否存在
只判断一位权限时,+和-一样
-MODE: 每一类用户都必须同时拥有为其制定的权限标准
例:文件权限644
-perm 644 查找文件权限为644的文件,可以匹配
-perm /222 查找有用户有写权限的文件,可以匹配
-perm /002 查找其他用户有写权限的文件,不能匹配
-perm -444 可以匹配
组合条件
-a 与(and)
-o 或(or)
-not,! 非(NOT)
若给出了多个查找条件而没有指定逻辑链接方式,默认为与(-a)
[ACTION] 对符合条件的文件做什么操作,默认为输出至屏幕
-print 输出至标准输出,默认操作
-ls 类似ls -l 的形式显示
-delete 删除查找到的文件
-fls /path/to/somefile
查找到的文件的长格式信息保存至指定文件中
-exec COMMAND {} \;
find把查找到的所有文件一次性地传递给-exec执行
执行命令,有些命令不接受过多参数,此时命令执行可能会失败,此时使用以下方式:
find | xargs COMMAND
{}是文件名占位符,用于引用查找到的文件名自身
注意:\;前必须有空格,\;二者之间不能都空格
-ok COMMAND {} \; 交互式-exec
六、vim
1. 介绍
同nano一样,vim也是一款全屏幕的编辑器,他是vi(visual Interface)编辑器的进化版(improved),功能异常强大。
vim是一个模式化的编辑器,这里介绍常用几种模式
- 编辑模式:默认处于该模式下,在该模式中,键盘操作通常被解释为编辑命令而非输入字符
- 输入模式:该模式下键盘的输入将被录入到屏幕
- 末行模式:即命令行模式,可在此进行复杂的操作
- 可视化模式:便于快捷查看、选定等
其界面如下:
2. 常用参数
vim [OPTIONS] /PATH/TO/SOMEFILE...
OPTIONS
-o 水平分割显示
-O 垂直分割显示
Ctrl+w,箭头 窗口间跳转
若打开单个文件,这里将不会分隔窗口
+N 打开文件并定位在第N行的行首
+/PATTERN 打开文件后,直接让光标处于第一个被PATTERN匹配到的行的行首
+ 打开文件并定位在最后一行
3. 模式间转换
-
编辑模式–>输入模式
- i:insert,在当前光标所在字符的前面,转换为输入模式
- a:append,在当前光标所在字符的后面,转换为输入模式
- o:在当前光标所在行的下方,新建一行,并转为输入模式
- I:在当前光标所在行的行首,转换为输入模式
- A:在当前光标所在行的行尾,转换为输入模式
- O:在当前光标所在行的上方,新建一行,并转换为输入模式 输入模式–>编辑模式
- ESC键 编辑模式–>末行模式
- : 末行模式–>编辑模式
- ESC
- 命令行有内容时可敲击多次ESC 编辑模式–>可视化模式
- v
4. 常用通配符
通配符 | 意义 |
---|---|
. | 当前行 |
$ | 最后一行 |
$-1 | 倒数第二行 |
+# | 向下的#行 |
5. 编辑模式
移动光标
逐字符移动
按键 | 动作 |
---|---|
h或← | 向左 |
l或→ | 向右 |
j或↓ | 向下 |
k或↑ | 向上 |
-
#COMMAND:可以移动#个字符如:
- 4l:向右移动4字符
- 6←:向左移动6字符
以单词为单位移动
按键 | 动作 |
---|---|
w | 移至下一个单词的词首 |
b | 调至当前或前一个单词词首 |
e | 跳至当前或下一个单词词尾 |
#COMMAND:可以移动#个单词
行内跳转
按键 | 动作 |
---|---|
0 | 数字0,跳至绝对行首 |
^ | 跳至行首的第一个非空白字符 |
$ | 跳至绝对行尾 |
行间跳转
按键 | 动作 |
---|---|
#G | 跳转至第#行 |
G | 跳转至最后一行 |
1G或gg | 跳转至第一行 |
句子间跳转
按键 | 动作 |
---|---|
) | 下一句 |
( | 上一句 |
段落间跳转
按键 | 动作 |
---|---|
} | 下一段 |
{ | 上一段 |
翻屏
按键 | 动作 |
---|---|
Ctrl+f | 向文件尾部翻一屏 |
Ctrl+b | 向文件首部翻一屏 |
Ctrl+d | 向文件尾部翻半屏 |
Ctrl+u | 向文件首部翻半屏 |
Enter | 按行向后翻 |
删除单个字符
按键 | 动作 |
---|---|
x | 删除光标所在处的单个字符 |
#x | 删除光标所在处及向后的共#个字符 |
删除命令:d
d命令跟跳转命令组合使用,用于删除光标当前位置到跳转到位置的字符,#d跳转符:如:
按键 | 动作 |
---|---|
3dw | 删除光标向后的3个单词 |
d^ | 删除至行首 |
d$ | 删除至行尾 |
dd | 删除当前光标所在行 |
#dd | 删除包括当前光标所在行在内的下#行 |
修改命令:c
即先删除内容,再转换为输入模式,用法同d命令,如
按键 | 动作 |
---|---|
c$ | 删除光标值行尾内容并转为输入模式 |
c^ | 删除光标值行首内容并转为输入模式 |
cc | 删除光标所在行内容并转为输入模式 |
#cc | 删除包括当前光标所在行在内的下#行并转为输入模式 |
复制命令:y
使用方法同删除命令,如
按键 | 动作 |
---|---|
c$ | 复制光标值行尾内容 |
c^ | 复制光标值行首内容 |
cc | 复制光标所在行内容 |
#cc | 复制包括当前光标所在行在内的下#行 |
粘贴命令:p
vim中编辑的内容可以撤销,最后一次删除的内容会被保存至内存的缓冲区中,可以用于下次粘贴至他处,相当于剪切
-
p(小写)
- 如果删除或复制的内容为整行内容,则粘贴至光标所在行的下方;
- 如果删除或复制的内容为非整行,则粘贴至光标所在字符的后面; P(大写)
- 如果删除或复制的内容为整行内容,则粘贴至光标所在行的上方;
- 如果删除或复制的内容为非整行,则粘贴至光标所在字符的前面
替换命令:r
先按r,再按下字符,可以将当前光标所在的字符替换的键入的字符
#r:向后替换#个字符
可敲R进入替换模式,替换模式下键入的字符将直接替换原字符
撤销
按键 | 动作 |
---|---|
u | 撤销前一次的编辑操作 |
#u | 撤消指定次数的操作 |
U | 仅撤销光标所在行的编辑操作 |
Ctrl+r | 还原撤销 |
连续u命令可撤消此前的n次编辑操作,默认最多撤销50次操作
重复之前的操作
在编辑模式中,使用.可重复之前的操作
分屏显示
按键 | 动作 |
---|---|
Ctrl+w, s | 水平拆分窗口 |
Ctrl+w, v | 垂直拆分窗口 |
在窗口键切换的方式为:Ctrl+w,箭头
关闭文件
ZZ (大写)保存并退出
6. 可视化模式
该模式可以选中光标划过的所有字符
按键 | 动作 |
---|---|
v | 按字符选取 |
V | 按行选取 |
经常结合编辑命令:d,c,y
7. 末行模式
打开文件
按键 | 动作 |
---|---|
:e FILE | 打开新文件 |
:r FILE | 读取其他文件至当前文件 |
关闭文件
按键 | 动作 |
---|---|
:q | 不保存退出(若修改了文件内容则无法退出) |
:wq | 保存并退出 |
:x | 同: wq ,保存并退出 |
:q! | 强行不保存退出 |
:w | 保存(只读属性的文件无法保存) |
:w /PATH/TO/SOMEFILE | 另存为 |
:w! | 强行保存(管理员) |
qall | 退出所有文件 |
wall | 保存所有文件 |
移动光标
直接给出行号,回车即可
地址定界
使用地址定界的形式为:START,END
,如
定界操作 | 意义 |
---|---|
# | 第#行 |
m,n | 第m行到第n行 |
m,+n | 相对定界,从第m行开始,往后n行 |
. | 当前行 |
$ | 最后一行 |
$-2 | 倒数第3行 |
/PAT1/,/PAT2/ | 自光标处开始匹配,从第一次能够被模式一(PAT1)匹配到的行开始,到以第一次能够被模式二(PAT2)匹配到的行结束,中间的所有行,通常的使用形式为/PAT/,$ |
% | 全文,相当于1,$ |
编辑操作
末行模式中的编辑操作格式为:地址定界后跟一个编辑命令,可实现对范围内的内容进行相应的编辑操作。如:
指令 | 操作 |
---|---|
#d | 删除光标所在行与向下的行供#行 |
%y | 复制全部内容 |
m,nw /PATH/TO/SOMEWHERE | 将m行到n行的内容写入指定文件中 |
m,nr /PATH/FROM/SOMEFILE | 将m至n行的内容替换为指定文件中的内容 |
查找
指令 | 操作 |
---|---|
/PATTERN | 从当前光标向尾部查找 |
?PATTERN | 从当前光标向首部查找 |
n | 与命令同方向 |
N | 与命令反方向 |
查找并替换:s
在末行模式下使用s命令,用法同sed中的s命令4
s命令默认只替换每行中第一次被模式匹配到的字符串,其使用格式为:
:地址定界s/查找模式/替换为的内容/修饰符
-
分隔符
- /为分隔符,可以换成其他字符,如s### s@@@ …
- 紧跟在s之后的字符,会被解析成定界符
- 若pattern中或string中有与分隔符相同的,使用\转义 查找模式
- 这里的模式支持正则表达式 替换为的内容
- 替换为的内容不支持正则表达式,但可以使用\1, \2, … 等后向引用,还可以使用&引用前面查找时查找到的整个内容 修饰符
-
修饰符 意义 g global,全局替换,替换(一行中)所有被模式匹配到的字符串,默认只替换每一行的第一个 i ignore-case,忽略字符大小写
如:
-
删除全文的行首的#
:%s@^#@@g
-
将1到30行行首是非#的行加上#
:1,30s@^[^#]@#&@g
-
将行首的空白字符替换为空
:%s/^[[:space:]]\+//
-
将每行开头为空白符的行首加一个#
:%s/^[[:space:]]/#&/
分屏显示
按键 | 动作 |
---|---|
:sp [FILE] | 水平分割显示 |
:vsp [FILE] | 垂直分割显示 |
文件间切换
当使用vim同时打开多个文件而没有指定分屏时,默认是将第一个文件全屏显示的,此时可以通过如下方式在打开的文件之间切换:
指令 | 操作 |
---|---|
: next | 切换至下一个文件 |
: previous | 切换至前一个文件 |
: last | 切换至最后一个文件 |
: first | 切换至第一个文件 |
与shell交互
即在vim中执行shell命令,在末行模式下输入!,后跟命令即可。
若在vim中编辑了内容,在未保存的情况下意外关闭,在下次编辑时vim将会警告,可以使用vim -r 恢复未保存的数据,删除同目录下的*.swp文件,亦可在警告窗口中根据提示进行操作
8. 定制vim的工作特性
在末行模式下使用set
可设定相关参数,用于修改vim的当前配置,不带任何参数的set
命令可查看set的帮助
显示或取消显示行号
: set number 显示行号
: set nu
: set nonumber 取消显示
: set nonu
设定忽略或区分字符大小写
: set ignorecase 忽略大小写
: set ic
: set noic 区分大小写
设定自动缩进
: set autoindent 自动缩进
: set ai
: set autoindent 取消缩进
: set noai
高亮搜索
: sethlsearch 高亮显示搜索到的文本
: set nohlsearch 取消高亮显示搜索到的文本
: nohl 取消高亮显示搜索到的文本
语法高亮
: syntax on 开启语法着色
: syntax off 关闭语法着色
高亮显示与之匹配的括号
:setshowmatch 显示与之匹配的括号
:set sm
:setshowmatch 取消显示
:set nosm
该操作可立即生效,作用域仅为当前vim进程
9. vim的配置文件
vim有两种配置文件
- /etc/vimrc:对所有用户生效
- ~/.vimrc:仅对当前用户生效,若不存在,可自行创建
通过将以上属性设置指令写入配置文件,可永久生效
10. 获取帮助
vim是一个很复杂的工具,这里介绍的只是基础用法,关于帮助的获取,可使用如下方式:
- : help:在末行模式下输入help和查看vim的帮助
- : help SUBJECT:help后跟一个关键字可查看该部分帮助
另外,vimtutor
命令中有关于vim的相关教程
七、特殊权限
1. 概念
记得之前在介绍umask时,其内容有4位,最高位就是特殊权限为的遮罩码。
Linux的特殊权限有三种,分别为
- SUID
- SGID
- Sticky
详细介绍之前, 先来回顾下安全上下文的概念。
-
安全上下文
-
- 任何一个可执行程序文件能不能启动为进程,取决发起者对程序文件是否拥有执行权限;
-
- 启动为进程之后,其进程的属主为发起者;进程的属组为发起者所属的组;
权限匹配模型:
- (1) 判断进程的属主,是否为被访问的文件的属主,若是,则应用属主权限,否则
- (2) 判断进程的数组,是否属于进程的数组,若是,则应用属组权限,否则
- (3) 应用其他权限
执行的进程是当前shell的子进程,shell以当前用户身份运行
SUID
- 意义:运行某程序时,相应进程的属主是程序文件自身的属主,而不是启动者
- 表现位置:表现为文件属主执行权限位上的s或S,如果FILE本身原来就有执行权限(x),则SUID显示为s,否则显示S
- 设置SUID权限
chmod u+s FILE … chmod u-s FILE …
SGID
- 意义:具有SGID的目录,用户在目录下创建时文件或目录时,其属组不再是用户自己的基本组,而是这个目录的属组,仅对目录有意义
- 表现位置:表现为文件(一般是目录)属组执行权限位上的s或S,如果FILE本身原来就有执行权限(x),则SGID显示为s,否则显示S
- 设定SGID权限
chmod g+s DIR … chmod g-s DIR …
Sticky
- 意义:对于公共可写的目录,用户可以创建文件,可以删除自己的文件,但无法删除别的用户的文件,仅对目录有意义
- 表现位置:表现为文件(一般是目录)其他用户执行位上的t或T,如果FILE本身原来就有执行权限(x),则Sticky显示为t,否则显示T
- 设定Sticky权限
chmod o+t DIR … chmod o-t DIR …
特殊权限位
SUID | SGID | Sticky | 八进制 |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 2 |
0 | 1 | 1 | 3 |
1 | 0 | 0 | 4 |
1 | 0 | 1 | 5 |
1 | 1 | 0 | 6 |
1 | 1 | 1 | 7 |
如此可使用chmod MMMM FILE
的方式对文件进行权限管理,如
chmod 5755 /tmp/test.mod
意为将/tmp/test.mod文件的权限设定为SUID,Sticky,rwxr-xr-x
八、FACL
FACL(Filesystem Access Control List)文件访问控制列表,是附加原有权限模型之上另一层权限控制机制,让普通用户能够控制赋权给另外的用户或组的赋权机制,保存至文件扩展属性信息中,利用文件扩展属性保存额外的访问控制权限。
getfacl
可以使用getfacl命令来读取FACL,如:
[root@localhost tmp]# getfacl test.facl
# file: test.facl
# owner: root
# group: root
user::rw-
user:user1:rwx
group::r--
mask::rwx
other::r--
输出信息有文件名、属主属组、以及权限信息,权限信息格式如下:
user|group:[USER_NAME|GROUP_NAME]:PERM
若用户名或组名为空,则标识该权限设定应用于属主或属组
-
其他说明
- 默认(没设置FACL时)只有文件名、属主、属组,以及9个权限位,设置之后会显示特定用户或组的权限
- 设置FACL时,超出mask给出的权限,但没有设置时,mask将自动变化为每次设置的最高权限
- 若文件设置了FACL,则在ls -l查看时,权限位后会多一个+,但在复制、归档等操作时,可能会丢失扩展属性
setfacl
setfacl用于设定文件的FACL,用法如下:
setfacl OPTION FILE
OPTION
-m 设定
u:USERNAME:PERM
g:GRPNAME:PERM
d:u:USERNAME:PERM
d:g:GRPNAME:PERM
当操作对象为目录时,使用d选项,使在该目录下创建的文件自动继承设置的扩展权限
m::PERM
设定mask
-x 取消
u:USERNAME
u:GRPNAME
m::PERM
取消mask
-b 清除所有FACL
-R 递归设置,对当前目录以及子目录生效
https://blog.csdn.net/xiyangyang410/article/details/85090293 ↩︎
读取方式后文将做介绍 ↩︎
关于特殊变量后续会详细介绍 ↩︎
后续将会介绍sed ↩︎