1. 基本命令
1.1 shell 格式输出
1 | $ echo 'Hello world !' |
打印彩色输出:
1 | # 彩色文本 |
1 | $ printf "%-5s %-10s %-4s\n" No Name Mark |
原理:
%-5s
指明了一个格式为左对齐且宽度为5的字符串替换( -
表示左对齐)。如果不用 -
指定对齐方式,字符串就采用右对齐形式。
%s
、 %c
、%d
和 %f
都是格式替换符(format substitution character),其所对应的参数可以置于带引号的格式字符串之后。
1.2 替换命令 tr
1 | # tr 是 translate的简写 |
1.3 打印变量
1 | $ var="value" |
1.4 设置环境变量
1 | # 在PATH中添加一条新路径 |
1.5 Shell中三种引号的用法
1 | # 单引号 |
1.6 获得字符串的长度
1 | # 用法 |
1.7 识别当前shell
1 | $ echo $SHELL |
1.8 使用shell进行数学运算
在Bash shell环境中,可以利用 let
、(( ))
和[]
执行基本的算术操作。而在进行高级操作时,expr
和 bc
这两个工具也会非常有用。
使用 let
时,变量名之前不需要再添加 $
1 | $ no1=4 |
1 | # 操作符[]的使用方法和let命令类似 |
1 | # 使用(())时,变量名之前需要加上$ |
1 | # expr同样可以用于基本算术操作 |
bc是一个用于数学运算的高级工具,这个精密计算器包含了大量的选项 。此处不多介绍。
1.9 shell中各种括号的作用()、(())、[]、[[]]、{}
1.9.1 小括号,圆括号()
1、单小括号 ( )
- 命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。
- 命令替换。等同于
cmd
,shell扫描一遍命令行,发现了$(cmd)结构
,便将$(cmd)
中的cmd执行一次,得到其标准输出,再将此输出放到原来命令。有些shell不支持,如tcsh。 - 用于初始化数组。如:array=(a b c d)。
2、双小括号 (( ))
- 整数扩展。这种扩展计算是整数型的计算,不支持浮点型。((exp))结构扩展并计算一个算术表达式的值,如果表达式的结果为0,那么返回的退出状态码为1,或者 是”假”,而一个非零值的表达式所返回的退出状态码将为0,或者是”true”。若是逻辑判断,表达式exp为真则为1,假则为0。
- 只要括号中的运算符、表达式符合C语言运算规则,都可用在
$((exp))
中,甚至是三目运算符。作不同进位(如二进制、八进制、十六进制)运算时,输出结果全都自动转化成了十进制。如:echo $((16#5f)) 结果为95 (16进位转十进制)。 - 单纯用 (( )) 也可重定义变量值,比如 a=5; ((a++)) 可将 $a 重定义为6。
- 常用于算术运算比较,双括号中的变量可以不使用
$
符号前缀。括号内支持多个表达式用逗号分开。 只要括号中的表达式符合C语言运算规则,比如可以直接使用for((i=0;i<5;i++)), 如果不使用双括号, 则为for i inseq 0 4
或者for i in {0..4}。再如可以直接使用if (($i<5))
, 如果不使用双括号, 则为if [ $i -lt 5 ]
。
1.9.2 中括号,方括号[]
1、单中括号 []
- bash 的内部命令,[和test是等同的。如果我们不用绝对路径指明,通常我们用的都是bash自带的命令。if/test结构中的左中括号是调用test的命令标识,右中括号是关闭条件判断的。这个命令把它的参数作为比较表达式或者作为文件测试,并且根据比较的结果来返回一个退出状态码。if/test结构中并不是必须右中括号,但是新版的Bash中要求必须这样。
- Test和[]中可用的比较运算符只有==和!=,两者都是用于字符串比较的,不可用于整数比较,整数比较只能使用-eq,-gt这种形式。无论是字符串比较还是整数比较都不支持大于号小于号。如果实在想用,对于字符串比较可以使用转义形式,如果比较”ab”和”bc”:[ ab \< bc ],结果为真,也就是返回状态为0。[ ]中的逻辑与和逻辑或使用-a 和-o 表示。
- 字符范围。用作正则表达式的一部分,描述一个匹配的字符范围。作为test用途的中括号内不能使用正则。
- 在一个array 结构的上下文中,中括号用来引用数组中每个元素的编号。
2、双中括号 [[ ]]
- [[是 bash 程序语言的关键字。并不是一个命令,[[ ]] 结构比[ ]结构更加通用。在[[和]]之间所有的字符都不会发生文件名扩展或者单词分割,但是会发生参数扩展和命令替换。
- 支持字符串的模式匹配,使用=~操作符时甚至支持shell的正则表达式。字符串比较时可以把右边的作为一个模式,而不仅仅是一个字符串,比如[[ hello == hell? ]],结果为真。[[ ]] 中匹配字符串或通配符,不需要引号。
- 使用[[ … ]]条件判断结构,而不是[ … ],能够防止脚本中的许多逻辑错误。比如,&&、||、<和> 操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用
if [[ $a != 1 && $a != 2 ]]
, 如果不适用双括号, 则为if [ $a -ne 1] && [ $a != 2 ]
或者if [ $a -ne 1 -a $a != 2 ]
。 - bash把双中括号中的表达式看作一个单独的元素,并返回一个退出状态码。
1.9.3 大括号、花括号 {}
1)常规用法
- 大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt
- 代码块,又被称为内部组,这个结构事实上创建了一个匿名函数 。与小括号中的命令不同,大括号内的命令不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开,最后一个也必须有分号。{}的第一个命令和左括号之间必须要有一个空格。
2)几种特殊的替换结构
1 | ${var:-string},${var:+string},${var:=string},${var:?string} |
${var:-string}
和${var:=string}:
若变量var为空,则用在命令行中用string来替换${var:-string}
,否则变量var不为空时,则用变量var的值来替换${var:-string}
;对于${var:=string}
的替换规则和${var:-string}
是一样的,所不同之处是${var:=string}
若var为空时,用string替换${var:=string}
的同时,把string赋给变量var: ${var:=string}
很常用的一种用法是,判断某个变量是否赋值,没有的话则给它赋上一个默认值。${var:+string}
的替换规则和上面的相反,即只有当var不是空的时候才替换成string,若var为空时则不替换或者说是替换成变量 var的值,即空值。(因为变量var此时为空,所以这两种说法是等价的) 。${var:?string}
替换规则为:若变量var不为空,则用变量var的值来替换${var:?string}
;若变量var为空,则把string输出到标准错误中,并从脚本中退出。我们可利用此特性来检查是否设置了变量的值。
补充扩展:在上面这五种替换结构中string不一定是常值的,可用另外一个变量的值或是一种命令的输出。
3)四种模式匹配替换结构
模式匹配记忆方法:
1 | # 是去掉左边(在键盘上#在$之左边) |
1 | ${var%pattern},${var%%pattern},${var#pattern},${var##pattern} |
- 第一种模式:
${variable%pattern}
,这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最短的匹配模式
- 第二种模式:
${variable%%pattern}
,这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式 - 第三种模式:
${variable#pattern}
这种模式时,shell在variable中查找,看它是否一给的模式pattern开始,如果是,就从命令行把variable中的内容去掉左边最短的匹配模式 - 第四种模式:
${variable##pattern}
这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式
这四种模式中都不会改变variable的值,其中,只有在pattern中使用了匹配符号时,%和%%,#和##才有区别。结构中的pattern支持通配符,表示零个或多个任意字符,?表示仅与一个任意字符匹配,[…]表示匹配中括号里面的字符,[!…]表示不匹配中括号里面的字符。
4)字符串提取和替换
1 | ${var:num},${var:num1:num2},${var/pattern/pattern},${var//pattern/pattern} |
- 第一种模式:
${var:num}
,这种模式时,shell在var中提取第num个字符到末尾的所有字符。若num为正数,从左边0处开始;若num为负数,从右边开始提取字串,但必须使用在冒号后面加空格或一个数字或整个num加上括号,如${var: -2}
、${var:1-3}
或${var:(-2)}
。 - 第二种模式:
${var:num1:num2}
,num1是位置,num2是长度。表示从$var字符串的第$num1
个位置开始提取长度为$num2的子串。不能为负数。 - 第三种模式:
${var/pattern/pattern}
表示将var字符串的第一个匹配的pattern替换为另一个pattern。。 - 第四种模式:
${var//pattern/pattern}
表示将var字符串中的所有能匹配的pattern替换为另一个pattern。
1.9.4 符号$后的括号
${a}
变量a的值, 在不引起歧义的情况下可以省略大括号。$(cmd)
命令替换,和cmd
效果相同,结果为shell命令cmd的输,过某些Shell版本不支持$()
形式的命令替换, 如tcsh。$((expression))
和exprexpression
效果相同, 计算数学表达式exp的数值, 其中exp只要符合C语言的运算规则即可, 甚至三目运算符和逻辑表达式都可以计算。
1.9.5 多条命令执行
- 单小括号,
(cmd1;cmd2;cmd3)
新开一个子shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后可以没有分号。 - 单大括号,
{ cmd1;cmd2;cmd3;}
在当前shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后必须有分号, 第一条命令和左括号之间必须用空格隔开。
对 {}
和 ()
而言, 括号中的重定向符只影响该条命令,而括号外的重定向符影响到括号中的所有命令。
1.10 Shell特殊变量 `$0, $#, $*, $@, $?, ### 和命令行参数
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名。 |
$n | 传递给脚本或函数的参数。n是一个数字,表示几个参数。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有采纳数。被双引号(“ “)包含是,与$* 稍有不同。 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前shell进程ID。对于shell脚本,就是这个脚本所在的进程ID。 |
1.10.1 命令行参数
运行脚本时传递给脚本的参数称为命令行参数。命令行参数用 $n
表示,例如,$1
表示第一个参数,$2
表示第二个参数,依次类推。
1.10.2 $*
和 $@
的区别
$*
和 $@
都表示传递给函数或脚本的所有参数,不被双引号(“ “)包含时,都以"$1" "$2" … "$n"
的形式输出所有参数。
但是当它们被双引号(“ “)包含时,"$*"
会将所有的参数作为一个整体,以"$1 $2 … $n"
的形式输出所有参数;"$@"
会将各个参数分开,以 "$1" "$2" … "$n"
的形式输出所有参数。
1.10.3 退出状态
$?
可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。
退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。
不过,也有一些命令返回其他值,表示不同类型的错误。
$?
也可以表示函数的返回值,此处不展开。
1.11 Shell重定向
1、重定向符号
1 | > 输出重定向到一个文件或设备 覆盖原来的文件 |
2、标准输入刷出
1 | 在 bash 命令执行的过程中,主要有三种输出入的状况,分别是: |
3、使用实例
1 | # & 是一个描述符,如果1或2前不加&,会被当成一个普通文件。 |
要在终端中打印stdout,同时将它重定向到一个文件中,那么可以这样使用tee 。
1 | # 用法:command | tee FILE1 FILE2 |
1.12 Shell数组和关联数组
1.12.1 简介
数组是Shell脚本非常重要的组成部分,它借助索引将多个独立的独立的数据存储为一个集合。普通数组只能使用整数作为数组索引,关联数组不仅可以使用整数作为索引,也可以使用字符串作为索引。通常情况下,使用字符串做索引更容易被人们理解。Bash从4.0之后开始引入关联数组。
1.12.2 定义打印普通数组
数组的方法有如下几种:
1 | #在一行上列出所有元素 |
注意:第一种方法要使用圆括号,否则后面会报错。
数组元素的方法有如下几种:
1 | $ echo ${array_var[0]} #输出结果为 test1 |
注意:在ubuntu 14.04中,shell脚本要以#!/bin/bash开头,且执行脚本的方式为 bash test.sh。
1.12.3 定义打印关联数组
定义关联数组
在关联数组中,可以使用任何文本作为数组索引。定义关联数组时,首先需要使用声明语句将一个变量声明为关联数组,然后才可以在数组中添加元素,过程如下:
1 | $ declare -A ass_array #声明一个关联数组 |
注意:对于普通数组,使用上面的方法依然可以列出索引列表,在声明关联数组以及添加数组元素时,都不能在前面添加美元符$。
1.13 使用别名
alias命令的作用只是暂时的。一旦关闭当前终端,所有设置过的别名就失效了。为了使别名设置一直保持作用,可以将它放入~/.bashrc文件中。因为每当一个新的shell进程生成时,都会执行 ~/.bashrc中的命令。
1 | $ alias install='sudo apt-get install' |
1.14 获取、设置日期和延时
时间方面 :
1 | % : 印出 |
日期方面 :
1 | %a : 星期几 (Sun..Sat) |
若是不以加号作为开头,则表示要设定时间,而时间格式为 MMDDhhmm[[CC]YY][.ss]
,其中:
1 | MM 为月份, |
参数 :
-d datestr : 显示 datestr 中所设定的时间 (非系统时间)
–help : 显示辅助讯息
-s datestr : 将系统时间设为 datestr 中所设定的时间
-u : 显示目前的格林威治时间
–version : 显示版本编号
例子:
1 | $ date # 获取日期 |
1.15 脚本调试
1.15.1使用选项–x,启用shell脚本的跟踪调试功能
1 | $ bash -x script.sh |
1.15.2 使用set -x和set +x对脚本进行部分调试
1 | #!/bin/bash |
- set –x:在执行时显示参数和命令。
- set +x:禁止调试。
- set –v:当命令进行读取时显示输入。
- set +v:禁止打印输入。
1.15.3 通过传递 _DEBUG环境变量调试
1 | #!/bin/bash |
可以将调试功能置为”on”来运行上面的脚本:
1 | $ _DEBUG=on ./script.sh |
我们在每一个需要打印调试信息的语句前加上DEBUG。如果没有把 _DEBUG=on传递给脚本,那么调试信息就不会打印出来。在Bash中,命令 :
告诉shell不要进行任何操作。
1.15.4 利用shebang来进行调试
shebang的妙用
把shebang从 #!/bin/bash
改成 #!/bin/bash -xv
,这样一来,不用任何其他选项就可以启用调试功能了。
1.16 函数参数
1 | $0 # 脚本名 |
导出函数:
函数也能像环境变量一样用export导出,如此一来,函数的作用域就可以扩展到子进程中,例如:
1 | export -f fname |
1.17 read命令
1 | # 从输入中读取n个字符并存入变量 |
1.18 条件比较与测试
1 | # if条件 |
if的条件判断部分可能会变得很长,但可以用逻辑运算符将它变得简洁一些:
1 | [ condition ] && action # 如果condition为真,则执行action |
&&
是逻辑与运算符, ||
是逻辑或运算符。编写Bash脚本时,这是一个很有用的技巧。现在来了解一下条件和比较操作。
算术比较:
-gt
:大于。-lt
:小于。-ge
:大于或等于。-le
:小于或等于。
可以按照下面的方法结合多个条件进行测试:
1 | [ $var1 -ne 0 -a $var2 -gt 2 ] #使用逻辑与-a |
文件系统相关测试:
我们可以使用不同的条件标志测试不同的文件系统相关的属性。
[ -f $file_var ]
:如果给定的变量包含正常的文件路径或文件名,则返回真。[ -x $var ]
:如果给定的变量包含的文件可执行,则返回真。[ -d $var ]
:如果给定的变量包含的是目录,则返回真。[ -e $var ]
:如果给定的变量包含的文件存在,则返回真。[ -c $var ]
:如果给定的变量包含的是一个字符设备文件的路径,则返回真。[ -b $var ]
:如果给定的变量包含的是一个块设备文件的路径,则返回真。[ -w $var ]
:如果给定的变量包含的文件可写,则返回真。[ -r $var ]
:如果给定的变量包含的文件可读,则返回真。[ -L $var ]
:如果给定的变量包含的是一个符号链接,则返回真。
字符串比较:
使用字符串比较时,最好用双中括号,因为有时候采用单个中括号会产生错误,所以最好避开它们。
可以用下面的方法检查两个字符串,看看它们是否相同。
[[ $str1 = $str2 ]]
:当str1等于str2时,返回真。也就是说, str1和str2包含
的文本是一模一样的。[[ $str1 == $str2 ]]
:这是检查字符串是否相等的另一种写法。
也可以检查两个字符串是否不同。
[[ $str1 != $str2 ]]
:如果str1和str2不相同,则返回真。
我们还可以检查字符串的字母序情况,具体如下所示。
[[ $str1 > $str2 ]]
:如果str1的字母序比str2大,则返回真。[[ $str1 < $str2 ]]
:如果str1的字母序比str2小,则返回真。[[ -z $str1 ]]
:如果str1包含的是空字符串,则返回真。[[ -n $str1 ]]
:如果str1包含的是非空字符串,则返回真。
使用逻辑运算符 && 和 || 能够很容易地将多个条件组合起来:
1 | if [[ -n $str1 ]] && [[ -z $str2 ]] |
test命令可以用来执行条件检测。用test可以避免使用过多的括号。之前讲过的[]中的测试条件同样可以用于test命令。
1 | if [ $var -eq 0 ]; then echo "True"; fi |
补充内容
1. 利用子shell生成一个独立的进程
子shell本身就是独立的进程。可以使用 ( )
操作符来定义一个子shell :
1 | pwd; |
2. 无限循环的实例
1 | repeat() { while true; do $@ && return; done } |
工作原理:
函数repeat,它包含了一个无限while循环,该循环执行以参数形式(通过 $@
访问)传入函数的命令。如果命令执行成功,则返回,进而退出循环。
一种更快的做法 :
在大多数现代系统中, true
是作为 /bin
中的一个二进制文件来实现的。
这就意味着每执行一次while循环, shell就不得不生成一个进程。
如果不想这样,可以使用shell内建的:
命令,它总是会返回为0的退出码:
1 | repeat() { while :; do $@ && return; done } |
尽管可读性不高,但是肯定比第一种方法快。
2. 命令之乐
2.1 cat命令
1 | # 摆脱多余的空白行 |
2.2 find命令
1 | # 列出当前目录及子目录下所有的文件和文件夹 |
1、find命令有一个选项 -iname
(忽略字母大小写)
1 | $ ls |
2、如果想匹配多个条件中的一个,可以采用OR条件操作 :
1 | $ ls |
3、选项-path的参数可以使用通配符来匹配文件路径。 -name
总是用给定的文件名进行匹配。-path
则将文件路径作为一个整体进行匹配。例如 :
1 | $ find /home/users -path "*/slynux/*" -print |
4、选项 -regex
的参数和 -path
的类似,只不过 -regex
是基于正则表达式来匹配文件路径的。
1 | $ ls |
5、find也可以用“!”否定参数的含义。例如:
1 | $ ls |
6、基于目录深度的搜索
1 | # 深度选项-maxdepth和 -mindepth来限制find命令遍历的目录深度 |
注:-maxdepth和-mindepth应该作为find的第三个参数出现。如果作为第4个或之后的参数,就可能会影响到find的效率,因为它不得不进行一些不必要的检查。
根据文件类型搜索
7、根据文件类型搜索
-type
可以对文件搜索进行过滤
文件类型 | 类型参数 |
---|---|
普通文件 | f |
符号链接 | l |
目录 | d |
字符设备 | c |
块设备 | b |
套接字 | s |
FIFO | p |
8、根据文件时间进行搜索
- 访问时间(-atime):用户最近一次访问文件的时间。
- 修改时间(-mtime):文件内容最后一次被修改的时间。
- 变化时间(-ctime):文件元数据(例如权限或所有权)最后一次改变的时间。
-atime、 -mtime、 -ctime可作为find的时间选项。它们可以用整数值指定,单位是天。这些整数值通常还带有 - 或 + : - 表示小于, + 表示大于。
1 | # 打印出在最近7天内被访问过的所有文件: |
-atime、 -mtime以及-ctime都是基于时间的参数,其计量单位是“天”。还有其他一些基于时间的参数是以分钟作为计量单位的。这些参数包括:
- -amin(访问时间)
- -mmin(修改时间)
- -cmin(变化时间)
使用 -newer
,我们可以指定一个用于比较时间戳的参考文件,然后找出比参考文件更新的(更近的修改时间)所有文件
1 | # 找出比file.txt修改时间更近的所有文件: |
9、基于文件大小的搜索
1 | $ find . -type f -size +2k |
- b —— 块(512字节)
- c —— 字节
- w —— 字(2字节)
- k —— 1024字节
- M —— 1024k字节
- G —— 1024M字节
10、删除匹配的文件
-delete
可以用来删除find查找到的匹配文件。
1 | # 删除当前目录下所有的 .swp文件: |
11、基于文件权限和所有权的匹配
1 | $ find . -type f -perm 644 -print |
-perm指明find应该只匹配具有特定权限值的文件。
12、利用find执行命令或动作
find命令可以借助选项-exec与其他命名进行结合。 -exec算得上是find最强大的特性之一。
1 | $ find . -type f -user root -exec chown slynux {} \; |
-exec
结合多个命令 :
我们无法在-exec参数中直接使用多个命令。它只能够接受单个命令,不过我们可以耍一个小花招。把多个命令写到一个shell脚本中(例如command.sh),然后在-exec中使用这个脚本:
1 | -exec ./commands.sh {} \; |
13、让find跳过特定的目录
1 | $ find devel/source_path \( -name ".git" -prune \) -o \( -type f -print \) |
\( -name ".git" -prune \)
的作用是用于进行排除,它指明了 .git目录应该被排除在外,而\( -type f -print \)
指明了需要执行的动作。这些动作需要被放置在第二个语句块中(打印出所有文件的名称和路径)。
2.3 玩转xargs
xargs
擅长将标准输入数据转换成命令行参数。
xargs
命令把从 stdin接收到的数据重新格式化,再将其作为参数提供给其他命令。
2.3.1 将多行输入转换成单行输出
只需要将换行符移除,再用” “(空格)进行代替,就可以实现多行输入的转换。
1 | $ cat example.txt # 样例文件 |
2.3.2 将单行输入转换成多行输出
指定每行最大的参数数量 n
,我们可以将任何来自stdin的文本划分成多行,每行 n
个参数。
1 | $ cat example.txt | xargs -n 3 |
2.3.3 定制定界符
用 -d
选项为输入指定一个定制的定界符:
1 | $ echo "splitXsplitXsplitXsplit" | xargs -d X |
在这里,我们明确指定X作为输入定界符,而在默认情况下, xargs采用内部字段分隔符(空格)作为输入定界符。
2.3.4 读取stdin,将格式化参数传递给命令
-I
指定替换字符串,这个字符串在xargs扩展时会被替换掉。如果将 -I
与 xargs
结合使用,对于每一个参数,命令都会被执行一次。
1 | $ cat args.txt |
-I {}
指定了替换字符串。对于每一个命令参数,字符串 {}
都会被从stdin读取到的参数替换掉。
使用 -I
的时候,命令以循环的方式执行。
xargs和find算是一对死党。两者结合使用可以让任务变得更轻松。 不过人们通常却是以一种错误的组合方式使用它们。例如:
1 | $ find . -type f -name "*.txt" -print | xargs rm -f |
这样做很危险。 有时可能会删除不必要删除的文件。
只要我们把 find
的输出作为 xargs
的输入,就必须将 -print0
与 find
结合使用,以字符null('\0')
来分隔输出。
1 | $ find . -type f -name "*.txt" -print0 | xargs -0 rm -f |
2.4 校验和与核实
校验和(checksum)程序用来从文件中生成校验和密钥,然后利用这个校验和密钥核实文件的完整性。文件可以通过网络或任何存储介质分发到不同的地点。
最知名且使用最为广泛的校验和技术是md5sum和SHA-1。它们对文件内容使用相应的算法来生成校验和。
1 | $ md5sum filename |
计算SAH-1串的命令是sha1sum。其用法和md5sum的非常相似。只需要把先前讲过的那些命令中的md5sum替换成sha1sum就行了,记住将输入文件名从file_sum.md5改为file_sum.sha1。
对目录进行校验:
1 | $ md5deep -rl directory_path > directory.md5 |
2.4.1 加密工具与散列
crypt
、 gpg
、 base64
、 md5sum
、 sha1sum
以及 openssl
的用法。
1)crypt是一个简单的加密工具,它从stdin接受一个文件以及口令作为输入,然后将加密数据输出到Stdout(因此要对输入、输出文件使用重定向)。
1 | $ crypt <input_file >output_file |
2)gpg(GNU隐私保护)是一种应用广泛的工具,它使用加密技术来保护文件,以确保数据在送达目的地之前无法被读取。这里我们讨论如何加密、解密文件。
1 | # 用gpg加密文件: |
3)Base64是一组相似的编码方案,它将ASCII字符转换成以64为基数的形式,以可读的ASCII字符串来描述二进制数据。 base64命令可以用来编码/解码Base64字符串。要将文件编码为Base64格式,可以使用:
1 | $ base64 filename > outputfile |
4)md5sum与sha1sum都是单向散列算法,均无法逆推出原始数据。它们通常用于验证数据完整性或为特定数据生成唯一的密钥:
1 | $ md5sum file |
这种类型的散列算法是存储密码的理想方案。密码使用其对应的散列值来存储。如果某个用户需要进行认证,读取该用户提供的密码并转换成散列值,然后将其与之前存储的散列值进行比对。如果相同,用户就通过认证,被允许访问;否则,就会被拒绝访问。
5)openssl
用openssl生成shadow密码。 shadow密码通常都是salt密码。所谓SALT就是额外的一个字符串,用来起一个混淆的作用,使加密更加不易被破解。 salt由一些随机位组成,被用作密钥生成函数的输入之一,以生成密码的salt散列值。
1 | $ opensslpasswd -1 -salt SALT_STRING PASSWORD |
2.5 排序、唯一与重复
1 | # 对一组文件进行排序: |
检查文件是否已经排序过:
1 | #!/bin/bash |
-k
指定了排序应该按照哪一个键(key)来进行。键指的是列号,而列号就是执行排序时的依据。 -r
告诉sort命令按照逆序进行排序。例如:
1 | # 依据第1列,以逆序形式排序 |
有时文本中可能会包含一些像空格之类的不必要的多余字符。如果需要忽略这些字符,并以字典序进行排序,可以使用:
1 | $ sort -bd unsorted.txt |
sort选项:
1 | -b:忽略每行前面开始出的空格字符; |
uniq选项:
1 | -c或——count:在每列旁边显示该行重复出现的次数; |
wc选项:
1 | -c或--bytes或——chars:只显示Bytes数; # 统计字符数 |
2.6 临时文件命名与随机数
1 | # 创建临时文件: |
如果提供了定制模板, X会被随机的字符(字母或数字)替换。注意, mktemp正常工作的前提是保证模板中只少要有3个X。
2.7 split 分割文件和数据
1 | # 将文件分割成多个大小为10KB的文件 |
上面的命令将data.file分割成多个文件,每一个文件大小为10KB。这些文件以xab、 xac、 xad的形式命名。这表明它们都有一个字母后缀。如果想以数字为后缀,可以另外使用-d参数。此外,使用 -a length可以指定后缀长度:
1 | $ split -b 10k data.file -d -a 4 |
除了k(KB)后缀,我们还可以使用M(MB)、 G(GB)、 c(byte)、 w(word)等后缀。
1 | # 为分割后的文件指定文件名前缀 |
csplit。它能够依据指定的条件和字符串匹配选项对日志文件进行分割。
1 | $ cat server.log |
有关这个命令的详细说明如下。
- /SERVER/ 用来匹配某一行,分割过程即从此处开始。
- /[REGEX]/ 表示文本样式。包括从当前行(第一行)直到(但不包括)包含“SERVER”的匹配行。
- {*} 表示根据匹配重复执行分割,直到文件末尾为止。可以用{整数}的形式来指定分割执行的次数。
- -s 使命令进入静默模式,不打印其他信息。
- -n 指定分割后的文件名后缀的数字个数,例如01、 02、 03等。
- -f 指定分割后的文件名前缀(在上面的例子中, server就是前缀)。
- -b 指定后缀格式。例如%02d.log,类似于C语言中printf的参数格式。在这里文件名=前缀+后缀=server + %02d.log。
因为分割后的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我们删除了server00.log。
2.7.1 根据扩展名切分文件名$、
借助 %
操作符可以轻松将名称部分从 “名称.扩展名” 这种格式中提取出来。
1 | file_jpg="sample.jpg" |
将文件名的扩展名部分提取出来,这可以借助 # 操作符实现。
1 | extension=${file_jpg#*.} |
${VAR%.*}
的含义如下所述:
- 从 $VAR中删除位于 % 右侧的通配符(在前例中是.*)所匹配的字符串。通配符从右向左进行匹配。
- 给VAR赋值, VAR=sample.jpg。那么,通配符从右向左就会匹配到.jpg,因此,从 $VAR中删除匹配结果,就会得到输出sample。
%属于非贪婪(non-greedy)操作。它从右到左找出匹配通配符的最短结果。还有另一个操作符 %%,这个操作符与%相似,但行为模式却是贪婪的,这意味着它会匹配符合条件的最长的字符串。
操作符%%则用.*从右向左执行贪婪匹配(.fun.book.txt)。
${VAR#*.}
的含义如下所述:
从$VAR中删除位于#右侧的通配符(即在前例中使用的*.)所匹配的字符串。通配
符从左向右进行匹配。
和 %% 类似, #也有一个相对应的贪婪操作符 ##。
##
从左向右进行贪婪匹配,并从指定变量中删除匹配结果。
这里有个能够提取域名不同部分的实用案例。假定 URL="www.google.com"
:
1 | $ echo ${URL%.*} # 移除.*所匹配的最右边的内容 |
2.8 批量重命名和移动
1 | # 将 *.JPG更名为 *.jpg: |
3 以文件之名
3.1 生成任意大小的文件
1 | $ dd if=/dev/zero of=junk.data bs=1M count=1 |
该命令会创建一个1MB大小的文件junk.data。来看一下命令参数: if代表输入文件(input file),of代表输出文件(output file), bs代表以字节为单位的块大小(block size), count代表需要被复制的块数。
使用dd命令时一定得留意,该命令运行在设备底层。要是你不小心出了岔子,搞不好会把磁盘清空或是损坏数据。所以一定要反复检查dd命令所用的语法是否正确,尤其是参数of=。
单元大小 | 代码 |
---|---|
字节(1B) | c |
字(2B) | w |
块(512B) | b |
千字节(1024B) | k |
兆字节(1024KB) | M |
吉字节(1024MB) | G |
ls -lS
对当前目录下的所有文件按照文件大小进行排序,并列出文件的详细信息。
3.2 文件权限、所有权和粘滞位
用命令ls -l可以列出文件的权限:
1 | -rw-r--r-- 1 slynux slynux 2497 2010-02-28 11:22 bot.py |
-
—— 普通文件。- d —— 目录。
- c —— 字符设备。
- b —— 块设备。
- l —— 符号链接。
- s —— 套接字。
- p —— 管道。
1 | # 更改所有权 |
3.3 创建不可修改的文件
chattr能够将文件设置为不可修改。
1 | # 使用下列命令将一个文件设置为不可修改: |
3.4 查找符号链接及其指向目标
1 | # 创建符号链接: |
3.5 列举文件类型统计信息
1 | # 用下面的命令打印文件类型信息: |
3.6 使用环回文件
1 | # 下面的命令可以创建一个1GB大小的文件: |
3.7 生成 ISO 文件及混合型 ISO
1 | #用下面的命令从/dev/cdrom创建一个ISO镜像: |
3.8 diff命令
1 | - # 指定要显示多少行的文本。此参数必须与-c或-u参数一并使用。 |
生成目录的差异信息 :
1 | $ diff -Naur directory1 directory2 |
- -N:将所有缺失的文件视为空文件。
- -a:将所有文件视为文本文件。
- -u:生成一体化输出。
- -r:遍历目录下的所有文件。
1 | # 生成patch文件 |
3.9 more、less、head与tail命令
3.9.1 more文件内容输出查看工具
1 | $ more [参数选项] [文件] |
举例:
1 | # 显示提示,并从终端或控制台顶部显示; |
more 的动作指令:
1 | Enter # 向下n行,需要定义,默认为1行; |
其它命令通过管道和more结合的运用例子:
1 | $ ls -l /etc |more |
3.9.2 less查看文件内容工具
1 | -c # 从顶部(从上到下)刷新屏幕,并显示文件内容。而不是通过底部滚动完成刷新; |
less的动作命令:
1 | 回车键 # 向下移动一行; |
3.9.3 head
head 是显示一个文件的内容的前多少行:
1 | $ head -n 10 /etc/profile |
3.9.4 tail
tail 是显示一个文件的内容的最后多少行:
1 | $ tail -n 5 /etc/profile |
3.10 getopts 参数解析
3.10.1 getopts(shell内置命令)
1 | $ type getopt |
getopts不能直接处理长的选项(如:–prefix=/home等)
关于getopts的使用方法,可以man bash 搜索getopts。
getopts有两个参数,第一个参数是一个字符串,包括字符和“:”,每一个字符都是一个有效的选项,如果字符后面带有“:”,表示这个字符有自己的参数。getopts从命令中获取这些参数,并且删去了“-”,并将其赋值在第二个参数中,如果带有自己参数,这个参数赋值在 $OPTARG
中。提供getopts的shell内置了 $OPTARG
这个变变,getopts修改了这个变量。
这里变量 $OPTARG
存储相应选项的参数,而 $OPTIND
总是存储原始 $*
中下一个要处理的元素位置。while getopts ":a:bc" opt
#第一个冒号表示忽略错误;字符后面的冒号表示该选项必须有自己的参数
getopts后面的字符串就是可以使用的选项列表,每个字母代表一个选项,后面带:的意味着选项除了定义本身之外,还会带上一个参数作为选项的值,比如d:在实际的使用中就会对应-d 30,选项的值就是30;getopts字符串中没有跟随:的是开关型选项,不需要再指定值,相当于true/false,只要带了这个参数就是true。如果命令行中包含了没有在getopts列表中的选项,会有警告信息,如果在整个getopts字符串前面也加上个:,就能消除警告信息了。
两个特殊变量:
1 | $OPTIND # 特殊变量,option index,会逐个递增, 初始值为1 |
例子:
1 | echo $* |
1 | $ ./getopts.sh -a 11 -b -c |
3.10.2 getopt(一个外部工具)
具体用用法可以 man getopt
-o
表示短选项,两个冒号表示该选项有一个可选参数,可选参数必须紧贴选项,如 -carg
而不能是 -c arg
。
--long
表示长选项
例子:
1 | #!/bin/bash |
1 | $ ./getopt.sh --b-long abc -a -c33 remain |
3.11 只列出目录的各种方法
1 | # 使用ls –d: |
3.12 使用pushd和popd进行快速定位
使用pushd和popd时,可以无视cd命令。
1 | # 压入并切换路径: |
3.13 tree打印目录树
1 | # 重点标记出匹配某种样式的文件: |
4 让文件飞
4.1 正则表达式
正则表达式 | 描述 | 示例 | |||
---|---|---|---|---|---|
^ | 行起始标记 | ^tux 匹配以tux起始的行 | |||
$ | 行尾标记 | tux$ 匹配以tux结尾的行 | |||
. | 匹配任意一个字符 | Hack.匹配Hackl和Hacki,它只能匹配单个字符 | |||
[ ] | 匹配包含在 [字符] 之中的任意一个字符 | coo[kl] 匹配cook或cool | |||
[ ^ ] | 匹配除 [^字符] 之外的任意一个字符 |
9[^01] 匹配92、 93,但是不匹配91或90 |
|||
[ - ] | 匹配 [ ] 中指定范围内的任意一个字符 | [1-5] 匹配从1~5的任意一个数字 | |||
? | 匹配之前的项1次或0次 | colou?r 匹配color或colour,但是不能匹配colouur | |||
+ | 匹配之前的项1次或多次 | Rollno-9+ 匹配Rollno-99、Rollno-9,但是不能匹配Rollno- | |||
* | 匹配之前的项0次或多次 | co*l 匹配cl、 col、 coool等 | |||
( ) | 创建一个用于匹配的子串 | ma(tri)?x 匹配max或maxtrix | |||
{n} | 匹配之前的项n次 | [0-9]{3} 匹 配 任 意 一 个 三 位 数 , [0-9]{3} 可 以 扩 展 为[0-9][0-9][0-9] |
|||
{n, } | 之前的项至少需要匹配n次 | [0-9]{2,} 匹配任意一个两位或更多位的数字 | |||
{n, m} | 指定之前的项所必需匹配的最小次数和最大次数 | [0-9]{2,5} 匹配从两位数到五位数之间的任意一个数字 | |||
\ | 交替——匹配 \ | 两边的任意一项 | Oct (1st \ | 2nd) 匹配Oct 1st或Oct 2nd | |
\ | 转义符可以将上面介绍的特殊字符进行转义 | a\.b 匹配a.b,但不能匹配ajb。通过在 . 之间加上前缀 \ ,从而忽略了 . 的特殊意义 |
正则表达式 | 描述 |
---|---|
[:alnum:] | 所有的字母和数字 |
[:alpha:] | 所有字母 |
[:blank:] | 水平制表符,空白等 |
[:cntrl:] | 所有控制字符 |
[:digit:] | 所有的数字 |
[:graph:] |
所有可打印字符,不包括空格 |
[:lower:] | 所有的小写字符 |
[:print:] | 所有可打印字符,包括空格 |
[:punct:] | 所有的标点字符 |
[:space:] | 所有的横向或纵向的空白 |
[:upper:] | 所有大写字母 |
4.2 grep命令
1 | -a # 不要忽略二进制的数据。 |
1 | # 单个grep命令也可以对多个文件进行搜索: |
4.3 cut 按列切分文件
1 | # 显示第2列和第3列: |
记法 | 范围 |
---|---|
N - | 从第N个字节,字符或字段到行尾 |
N - M | 从第N个字节,字符或字段到第M个(包括第M个在内)字节、字符或字段 |
- M | 第1个字节,字符或字段到第M个(包括第M个在内)字节、字符或字段 |
结合下列选项将字段指定为某个范围内的字节或字符 :
- -b :表示字节
- -c :表示字符
- -f :用于定义字段
1 | $ cat range_fields.txt |
4.4 sed 进行文本替换
选项:
1 | -e <script> # 以选项中指定的script来处理输入的文本文件 |
命令:
1 | a\ # 在当前行下面插入文本。 |
sed 替换标记:
1 | g # 表示行内全面替换。 |
sed 元字符集:
1 | ^ # 匹配行开始,如:/^sed/匹配所有以sed开头的行。 |
1 | # sed可以替换给定文本中的字符串。 |
4.5 awk 进行高级文本处理
4.5.1 awk 常用命令选项
-F fs
fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value
赋值一个用户定义变量,将外部变量传递给awk
-f scripfile
从脚本文件中读取awk命令-m[fr] val
对val值设置内在限制,-mf
选项限制分配给val的最大块数目;-mr
选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
4.5.2 awk 脚本基本结构
1 | $ awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file |
4.5.3 awk 的工作原理
1 | $ awk 'BEGIN{ commands } pattern{ commands } END{ commands }' |
- 第一步:执行
BEGIN{ commands }
语句块中的语句 - 第二步:从文件或标准输入(stdin)读取一行,然后执行
pattern{ commands }
语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕 - 第三步:当读至输入流末尾时,执行
END{ commands }
语句块
4.5.4 awk 内置变量(预定义变量)
说明: [A][N][P][G]
表示第一个支持变量的工具,[A]=awk
、[N]=nawk
、[P]=POSIXawk
、[G]=gawk
1 | $n # 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。 |
1 | $ echo -e "line1 f2 f3nline2 f4 f5nline3 f6 f7" | awk '{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}' |
4.5.5 将外部变量值传递给awk
借助 -v
选项,可以将外部值(并非来自stdin)传递给awk:
1 | $ VAR=10000 |
4.5.6 awk 运算与判断
算数运算符:
运算符 | 描述 |
---|---|
+ - | 加、减 |
* / & | 乘,除与求余 |
+ - ! | 一元加、减和逻辑非 |
^ *** | 求幂 |
++ – | 增加或减少,作为前缀或后缀 |
1 | $ awk 'BEGIN{a="b";print a++,++a;}' |
注意:所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0
赋值运算符:
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值语句 |
逻辑运算符:
运算符 | 描述 | ||
---|---|---|---|
\ | \ | 逻辑或 | |
&& | 逻辑与 |
1 | $ awk 'BEGIN{a=1;b=2;print (a>5 && b<=2),(a>5 || b<=2);}' |
正则运算符:
运算符 | 描述 |
---|---|
~ ~! | 匹配正则表达式和不匹配正则表达式 |
1 | $ awk 'BEGIN{a="100testa";if(a ~ /^100*/){print "ok";}}' |
关系运算符:
运算符 | 描述 |
---|---|
< <= > >= != == | 关系运算符 |
1 | $ awk 'BEGIN{a=11;if(a >= 9){print "ok";}}' |
注意:> < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比较。两个都为数字才转为数值比较。字符串比较:按照ASCII码顺序比较。
其他运算符:
运算符 | 描述 |
---|---|
$ | 字段引用 |
空格 | 字符串连接符 |
? : | C条件表达式 |
in | 数组中是否存在某键值 |
1 | $ awk 'BEGIN{a="b";print a=="b"?"ok":"err";}' |
运算级优先级表:
级别 | 运算符 | 说明 | ||
---|---|---|---|---|
1 | =, +=, -=, *=, /=, %=, &=, ^=, \ | =, <<=, >>= | 赋值、运算 | |
2 | \ | \ | 逻辑或 | |
3 | && | 逻辑与 | ||
4 | \ | 按位或 | ||
5 | ^ | 按位异或 | ||
6 | & | 按位与 | ||
7 | ==, != | 等于、不等于 | ||
8 | <=, >=, <, > | 小于等于、大于等于、小于、大于 | ||
9 | <<, >> | 按位左移,按位右移 | ||
10 | +, - | 加、减 | ||
11 | *, /, % | 乘、除、取模 | ||
12 | !, ~ | 逻辑非、按位取反或补码 | ||
13 | -, + | 正、负 |
级别越高越优先
4.5.7 awk 高级输入输出
读取下一条记录:
awk中 next
语句使用:在循环逐行匹配,如果遇到 next
,就会跳过当前行,直接忽略下面语句。而进行下一行匹配。net语句一般用于多行合并:
1 | $ cat text.txt |
当记录行号除以2余1,就跳过当前行。下面的 print NR,$0
也不会执行。下一行开始,程序有开始判断 NR%2
值。这个时候记录行号是 :2
,就会执行下面语句块:'print NR,$0'
分析发现需要将包含有 “web” 行进行跳过,然后需要将内容与下面行合并为一行:
1 | $ cat text.txt |
简单地读取一条记录:
awk getline
用法:输出重定向需用到 getline函数
。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。
如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。
getline语法:getline var,变量var包含了特定行的内容。
awk getline从整体上来说,用法说明:
- 当其左右
无
重定向符|
或<
时:getline作用于当前文件,读入当前文件的第一行给其后跟的变量var
或$0
(无变量),应该注意到,由于awk在处理getline之前已经读入了一行,所以getline得到的返回结果是隔行的。 - 当其左右
有
重定向符|
或<
时:getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。
1 | # 执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量out,并打印它: |
关闭文件:
awk中允许在程序中关闭一个输入或输出文件,方法是使用awk的close语句。
1 | close("filename") |
filename可以是getline打开的文件,也可以是stdin,包含文件名的变量或者getline使用的确切命令。或一个输出文件,可以是stdout,包含文件名的变量或使用管道的确切命令。
输出到一个文件:
1 | $ echo | awk '{printf("hello word!n") > "datafile"}' |
4.5.8 设置字段定界符
默认的字段定界符是空格
,可以使用-F "定界符"
明确指定一个定界符:
1 | $ awk -F: '{ print $NF }' /etc/passwd |
在 BEGIN语句块
中则可以用 OFS=“定界符”
设置输出字段的定界符。
4.5.9 流程控制语句
条件判断语句:
1 | $ awk 'BEGIN{ |
每条命令语句后面可以用 ;
分号
结尾。循环语句:
while语句:
1 | $ awk 'BEGIN{ |
for循环:
格式1:
1 | $ awk 'BEGIN{ |
注:ENVIRON是awk常量,是子典型数组。
格式2:
1 | $ awk 'BEGIN{ |
do循环:
1 | $ awk 'BEGIN{ |
其他语句:
- break 当 break 语句用于 while 或 for 语句时,导致退出程序循环
- continue 当 continue 语句用于 while 或 for 语句时,使程序循环移动到下一个迭代
- next 能能够导致读入下一个输入行,并返回到脚本的顶部。这可以避免对当前输入行执行其他的操作过程
- exit 语句使主输入循环退出并将控制转移到END,如果END存在的话。如果没有定义END规则,或在END中应用exit语句,则终止脚本的执行
4.5.10 数组应用
1 | # 得到数组长度 |
4.5.11 内置函数
awk内置函数,主要分以下3种类似:算数函数、字符串函数、其它一般函数、时间函数。
算数函数:
格式 | 描述 |
---|---|
atan2( y, x ) | 返回 y/x 的反正切 |
cos( x ) | 返回 x 的余弦;x 是弧度 |
sin( x ) | 返回 x 的正弦;x 是弧度 |
exp( x ) | 返回 x 幂函数 |
log( x ) | 返回 x 的自然对数 |
sqrt( x ) | 返回 x 平方根 |
int( x ) | 返回 x 的截断至整数的值 |
rand( ) | 返回任意数字 n,其中 0 <= n < 1 |
srand( [expr] ) | 将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。 |
1 | $ awk 'BEGIN{OFMT="%.3f";fs=sin(1);fe=exp(10);fl=log(10);fi=int(3.1415);print fs,fe,fl,fi;}' |
字符串函数:
格式 | 描述 |
---|---|
gsub( Ere, Repl, [ In ] ) | 除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行 |
sub( Ere, Repl, [ In ] ) | 用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere 参数指定的扩展正则表达式的第一个具体值。sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录($0 记录变量) |
index( String1, String2 ) | 在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零) |
length [(String)] | 返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量) |
blength [(String)] | 返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量) |
substr( String, M, [ N ] ) | 返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。M 参数指定为将 String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度 |
match( String, Ere ) | 在 String 参数指定的字符串(Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0(零)。RSTART 特殊变量设置为返回值。RLENGTH 特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一) |
split( String, A, [Ere] ) | 将 String 参数指定的参数分割为数组元素 A[1], A[2], . . ., A[n],并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符(FS 特殊变量)来进行(如果没有给出 Ere 参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建 |
tolower( String ) | 返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义 |
toupper( String ) | 返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义 |
sprintf(Format, Expr, Expr, . . . ) | 根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr 参数指定的表达式并返回最后生成的字符串 |
注:Ere都可以是正则表达式。
1 | # gsub,sub使用 |
格式化字符串输出(sprintf使用)
格式化字符串格式:
格式 | 描述 |
---|---|
%d | 十进制有符号整数 |
%u | 十进制无符号整数 |
%f | 浮点数 |
%s | 字符串 |
%c | 单个字符 |
%p | 指针的值 |
%e | 指数形式的浮点数 |
%x | %X 无符号以十六进制表示的整数 |
%o | 无符号以八进制表示的整数 |
%g | 自动选择合适的表示法 |
1 | $ awk 'BEGIN{n1=124.113;n2=-1.224;n3=1.2345; printf("%.2f,%.2u,%.2g,%X,%on",n1,n2,n3,n1,n1);}' |
一般函数:
格式 | 描述 | |
---|---|---|
close( Expression ) | 用同一个带字符串值的 Expression 参数来关闭由 print 或 printf 语句打开的或调用 getline 函数打开的文件或管道。如果文件或管道成功关闭,则返回 0;其它情况下返回非零值。如果打算写一个文件,并稍后在同一个程序中读取文件,则 close 语句是必需的 | |
system(command ) | 执行 Command 参数指定的命令,并返回退出状态。等同于 system 子例程 | |
Expression \ | getline [ Variable ] | 从来自 Expression 参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。如果当前未打开将 Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程,此时 Command 参数取 Expression 参数的值且 Mode 参数设置为一个是 r 的值。只要流保留打开且 Expression 参数求得同一个字符串,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录 |
getline [ Variable ] < Expression | 从 Expression 参数指定的文件读取输入的下一个记录,并将 Variable 参数指定的变量设置为该记录的值。只要流保留打开且 Expression 参数对同一个字符串求值,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录 | |
getline [ Variable ] | 将 Variable 参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定 Variable 参数,则 $0 记录变量设置为该记录的值,还将设置 NF、NR 和 FNR 特殊变量 |
1 | # 打开外部文件(close用法) |
时间函数:
格式 | 描述 |
---|---|
函数名 | 说明 |
mktime( YYYY MM dd HH MM ss[ DST]) | 生成时间格式 |
strftime([format [, timestamp]]) | 格式化时间输出,将时间戳转为时间字符串 具体格式,见下表. |
systime() | 得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数 |
1 | # 建指定时间(mktime使用) |
strftime日期和时间格式说明符
格式 | 描述 |
---|---|
%a | 星期几的缩写(Sun) |
%A | 星期几的完整写法(Sunday) |
%b | 月名的缩写(Oct) |
%B | 月名的完整写法(October) |
%c | 本地日期和时间 |
%d | 十进制日期 |
%D | 日期 08/20/99 |
%e | 日期,如果只有一位会补上一个空格 |
%H | 用十进制表示24小时格式的时间 |
%I | 用十进制表示12小时格式的时间 |
%j | 从1月1日期一年中的第几天 |
%m | 十进制表示的月份 |
%M | 十进制表示的分钟 |
%p | 12小时表示法(AM/PM) |
%S | 十进制表示的秒 |
%U | 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) |
%w | 十进制表示的星期几(星期天是0) |
%W | 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) |
%x | 重新设置本地日期(08/20/99) |
%X | 重新设置本地时间(12 : 00 : 00) |
%y | 两位数字表示的年(99) |
%Y | 当前月份 |
%Z | 时区(PDT) |
%% | 百分号(%) |
4.6 find 对目录中的所有文件进行文本替换
1 | # 将所有.cpp文件中的Copyright替换成Copyleft: |
5 一团乱麻
5.1 wget命令
1 | -a<日志文件>: # 在指定的日志文件中记录资料的执行过程; |
1 | # 使用wget下载单个文件 |
测试下载链接:
当你打算进行定时下载,你应该在预定时间测试下载链接是否有效。我们可以增加–spider参数进行检查。
1 | $ wget --spider URL |
如果下载链接正确,将会显示:
1 | Spider mode enabled. Check if remote file exists. |
这保证了下载能在预定的时间进行,但当你给错了一个链接,将会显示如下错误:
1 | $ wget --spider url |
你可以在以下几种情况下使用–spider参数:
- 定时下载之前进行检查
- 间隔检测网站是否可用
- 检查网站页面的死链接
1 | # 增加重试次数 |
镜像网站:
1 | $ wget --mirror -p --convert-links -P ./LOCAL URL |
下载整个网站到本地。
- –mirror 开户镜像下载
- -p 下载所有为了html页面显示正常的文件
- –convert-links 下载后,转换成本地的链接
- -P ./LOCAL URL 保存所有文件和目录到本地指定目录
下载指定格式文件:
1 | $ wget -r -A.pdf url |
可以在以下情况使用该功能:
- 下载一个网站的所有图片
- 下载一个网站的所有视频
- 下载一个网站的所有PDF文件
FTP下载:
1 | $ wget ftp-url |
可以使用wget来完成ftp链接的下载。
使用wget匿名ftp下载:
1 | $ wget ftp-url |
使用wget用户名和密码认证的ftp下载:
1 | $ wget --ftp-user=USERNAME --ftp-password=PASSWORD url |
5.2 curl 命令
常见参数:
1 | -A/--user-agent <string> # 设置用户代理发送给服务器 |
1 | # 不显示进度信息使用--silent选项。 |
其他参数:
1 | -a/--append # 上传文件时,附加到目标文件 |
5.3 curl wget两种方法模拟http的get post请求
get请求:
1 | # 使用curl命令: |
1 | # 使用wget命令: |
post请求:
1 | # 使用curl命令(通过-d参数,把访问参数放在里面): |
1 | # 使用wget命令:(--post-data参数来实现) |
6 B计划
6.1 用tar归档
tar支持的参数包括: A
、 c
、 d
、 r
、 u
、 x
、 f
和 v
1 | # 用tar对文件进行归档: |
压缩tar归档文件:
归档文件通常被压缩成下列格式之一:
- file.tar.gz
- file.tar.bz2
- file.tar.lzma
不同的tar选项可以用来指定不同的压缩格式:
- -j 指定bunzip2格式;
- -z 指定gzip格式;
- –lzma 指定lzma格式。
1 | # 为了让tar支持根据扩展名自动进行压缩,使用 -a或 --auto-compress选项: |
6.2 用cpio归档
1 | # 创建测试文件: |
对于归档命令:
- -o 指定了输出;
- -v 用来打印归档文件列表。
在列出给定cpio归档文件所有内容的命令中:
- -i 用于指定输入;
- -t 表示列出归档文件中的内容。
当使用命令进行提取时, -d用来表示提取。 cpio在覆盖文件时不会发出提示。
6.3 使用gzip压缩数据
1 | # 要使用gzip压缩文件,可以使用下面的命令: |
1 | # 压缩归档文件 |
6.4 用 zip 归档和压缩
1 | # 对归档文件采用ZIP格式进行压缩: |
6.5 更快的归档工具 pbzip2
1 | # 压缩单个文件: |
6.6 创建压缩文件系统
squashfs是一种具有超高压缩率的只读型文件系统,这种文件系统能够将2GB~3GB的数据压缩成一个700MB的文件。
1 | # 添加源目录和文件,创建一个squashfs文件: |
6.7 使用 rsync 备份系统快照
rsync可以对位于不同位置的文件和目录进行同步,它利用差异计算以及压缩技术来最小化数据传输量。
rsync也支持压缩、加密等多种特性。
1 | # 将源目录复制到目的端: |
6.8 用 fsarchiver 创建全盘镜像
1 | # 创建文件系统/分区备份。 |
7 无网不利
7.1 设置网络
1 | # 手动设置网络接口的IP地址: |
7.2 traceroute 命令
traceroute,它可以显示分组途径的所有网关的地址。 traceroute信息可以帮助我们搞明白分组到达目的地需要经过多少跳(hop)。中途的网关或路由器的数量给出了一个测量网络上两个节点之间距离的度量
(metric)。 traceroute的输出如下:
1 | $ traceroute google.com |
7.3 列出网络上所有的活动主机 (fping)
fping的选项如下:
- 选项 -a指定打印出所有活动主机的IP地址;
- 选项 -u指定打印出所有无法到达的主机;
- 选项 -g指定从 “IP地址/子网掩码”记法或者”IP地址范围”记法中生成一组IP地址;
1 | $ fping -a 192.160.1/24 -g |
7.4 ssh 命令
1 | # SSH的压缩功能,选项-C启用这一功能: |
7.5 通过网络传输文件
计算机联网的主要目的就是资源共享。在资源共享方面,使用最多的是文件共享。有多种方法可以用来在网络中传输文件。这则攻略就讨论了如何用常见的协议FTP、 SFTP、 RSYNC和SCP传输文件。
通过FTP传输文件可以使用lftp命令,通过SSH连接传输文件可以使用sftp, RSYNC使用SSH与rsync命令, scp通过SSH进行传输。
文件传输协议(File Transfer Protocol, FTP) :
1 | # 要连接FTP服务器传输文件,可以使用: |
你可以在提示符后输入命令,如下所示。
- 用cd directory改变目录。
- 用lcd改变本地主机的目录。
- 用mkdir创建目录。
- 列出远程机器当前目录下的文件使用Is。
- 用get filename下载文件:
lftp username@ftphost:~> get filename
- 用put filename从当前目录上传文件:
lftp username@ftphost:~> put filename
- 用quit退出lftp会话。
FTP自动传输 :
ftp是另一个可用于FTP文件传输的命令。相比较而言, lftp的用法更灵活。 lftp和ftp为用户启动一个交互式会话(通过显示消息来提示用户输入)。
SFTP(Secure FTP,安全FTP) :
1 | $ cd /home/slynux |
rsync命令 :
rsync广泛用于网络文件复制及系统备份。
SCP(Secure Copy Program,安全复制程序) :
1 | $ scp filename user@remotehost:/home/path |
用SCP进行递归复制 :
1 | $ scp -r /home/slynux user@remotehost:/home/backups |
7.6 连接网线网络
我们需要用ifconfig分配IP地址和子网掩码才能连接上有线网络。对于无线网络来说,还需要其他工具(如iwconfig和iwlist)来配置更多的参数。
iwlist工具扫描并列出可用的无线网络。用下面的命令进行扫描:
1 | $ iwlist scan |
7.7 在本地挂载点上挂载远程驱动器
sshfs允许你将远程文件系统挂载到本地挂载点上。
1 | # 将位于远程主机上的文件系统挂载到本地挂载点上: |
7.8 网络流量与端口分析
列出系统中的开放端口以及运行在端口上的服务的详细信息,可以使用以下命令:
1 | $ lsof -i |
用netstat查看开放端口与服务 :
1 | # netstat -tnp列出开放端口与服务: |
7.9 创建套接字
最简单的方法就是使用netcat命令(或nc)。我们需要两个套接字:一个用来侦听,一个用来连接。
1 | # 设置侦听套接字: |
在网络上进行快速文件复制 :
1 | # 在接收端执行下列命令: |
7.10 iptables防火墙设置
1 | # 阻塞发送到特定IP地址的流量: |
8 当个好管家
8.1 监视磁盘使用情况
df
是disk free的缩写, du
是disk usage的缩写。
1 | # 找出某个文件(或多个文件)占用的磁盘空间: |
du提供磁盘使用情况信息,而df提供磁盘可用空间信息。
1 | $ df -h |
8.2 计算命令执行时间
- real: %e
- user: %U
- sys: %S
1 | $ time COMMAND |
三种不同类型的时:
- Real时间指的是挂钟时间(wall clock time),也就是命令从开始执行到结束的时间。这段时间包括其他进程所占用的时间片(time slice)以及进程被阻塞时所花费的时间(例如,为等待I/O操作完成所用的时间)。
- User时间是指进程花费在用户模式(内核之外)中的CPU时间。这是唯一真正用于执行进程所花费的时间。执行其他进程以及花费在阻塞状态中的时间并没有计算在内。
- Sys时间是指进程花费在内核中的CPU时间。它代表在内核中执行系统调用所使用的时间,这和库代码(library code)不同,后者仍旧运行在用户空间。与“user时间”类似,这也是真正由进程使用的CPU时间。
time命令 一些可以使用的参数:
参数 | 描述 |
---|---|
%C | 进行计时的命令名称以及命令行参数 |
%D | 进程非共享数据区域的大小,以KB为单位 |
%E | 进程使用的real时间(挂钟时间),显示格式为[小时:]分钟:秒 |
%x | 命令的退出状态 |
%k | 进程接收到的信号数量 |
%W | 进程被交换出主存的次数 |
%Z | 系统的页面大小。这是一个系统常量,但在不同的系统中,这个常量值也不同 |
%P | 进程所获得的CPU时间百分比。这个值等于user+system时间除以总运行时间。结果以百分比形式显示 |
%K | 进程的平均总(data+stack+text)内存使用量,以KB为单位 |
%w | 进程主动进行上下文切换的次数,例如等待I/O操作完成 |
%c | 进程被迫进行上下文切换的次数(由于时间片到期) |
8.3 收集与当前登录用户、启动日志及启动故障的相关信息
1 | # 获取当前登录用户的相关信息: |
8.4 使用 watch 监视命令输出
watch命令可以用来在终端中以固定的间隔监视命令输出。
1 | $ watch ls |
8.5 用 logrotate 管理日志文件
用一种被称为轮替(rotation)的技术来限制日志文件的体积,一旦它超过了限定的大小,就对其内容进行抽取(strip),同时将 日志文件中的旧条目存储到日志目录中的归档文件内。旧的日志文件就会得以保存以便随后参阅。
logrotate
的配置目录位于/etc/logrotate.d。
1 | $ cat /etc/logrotate.d/program |
配置文件中各个参数的含义:
参数 | 描述 |
---|---|
missingok | 如果日志文件丢失,则忽略;然后返回(不对日志文件进行轮替) |
notifempty | 仅当源日志文件非空时才对其进行轮替 |
size 30k | 限制实施轮替的日志文件的大小。可以用1M表示1MB |
compress | 允许用gzip压缩较旧的日志 |
weekly | 指定进行轮替的时间间隔。可以是weekly、 yearly或daily |
rotate 5 | 这是需要保留的旧日志文件的归档数量。在这里指定的是5,所以这些文件名将会是program.log.1.gz、 program.log.2.gz等直到program.log.5.gz |
create 0600 root root | 指定所要创建的归档文件的模式、用户以及用户组 |
8.6 用 syslog 记录日志
每一个标准应用进程都可以利用syslog记录日志信息。
使用命令logger通过syslogd记录日志。
Linux中一些重要的日志文件 :
日志文件 | 描述 |
---|---|
/var/log/boot.log | 系统启动信息 |
/var/log/httpd | Apache Web服务器日志 |
/var/log/messages | 发布内核启动信息 |
/var/log/auth.log | 用户认证日志 |
/var/log/dmesg | 系统启动信息 |
/var/log/mail.log | 邮件服务器日志 |
/var/log/Xorg.0.log | X服务器日志 |
1 | # 向系统日志文件/var/log/message中写入日志信息: |
8.7 通过监视用户登录找出入侵者
入侵者定义为:屡次试图登入系统达两分钟以上,并且期间的登录过程全部失败。凡是这类用户都应该被检测出来并生成包含以下细节信息的报告:
- 试图登录的账户
- 试图登录的次数
- 攻击者的IP地址
- IP地址所对应的主机
- 进行登录的时间段
为了处理SSH登录失败的情况,还得知道用户认证会话日志会被记录在日志文件/var/log/auth.log中。脚本需要扫描这个日志文件来检测出失败的登录信息,执行各种检查来获取所需要的数据。我们可以用host命令找出IP地址所对应的主机。
8.8 监视磁盘活动
1 | # 交互式监视, iotop的-o选项只显示出那些正在进行I/O活动的进程: |
8.9 检查磁盘及文件系统错误
使用fsck的各种选项对文件系统错误进行检查和修复。
1 | # 要检查分区或文件系统的错误,只需要将路径作为fsck的参数: |
9 管理重任
9.1 收集进程信息
1 | # 为了包含更多的信息,可以使用-f(表示full)来显示多列,如下所示: |
选项-o可以使用不同的参数:
参数 | 描述 |
---|---|
pcpu | CPU占用率 |
pid | 进程ID |
ppid | 父进程ID |
pmem | 内存使用率 |
comm | 可执行文件名 |
cmd | 简单命令 |
user | 启动进程的用户 |
nice | 优先级 |
time | 累计的CPU时间 |
etime | 进程启动后流逝的时间 |
tty | 所关联的TTY设备 |
euid | 有效用户ID |
stat | 进程状态 |
1 | # top, 默认会输出一个占用CPU最多的进程列表。输出结果每隔几秒就会更新。 |
9.2 which、 whereis、 file、 whatis与平均负载
1 | # which, which命令用来找出某个命令的位置。 |
9.3 杀死进程以及发送或响应信号
信号是Linux中的一种进程间通信机制。 当进程接收到一个信号时,它会通过执行对应的信号处理程序(signal handler)来进行响应。
1 | # 列出所有可用的信号: |
常用到的信号量:
- SIGHUP 1——对控制进程或终端的终结进行挂起检测(hangup detection)
- SIGINT 2——当按下Ctrl + C时发送该信号
- SIGKILL 9——用于强行杀死进程
- SIGTERM 15——默认用于终止进程
- SIGTSTP 20——当按下Ctrl + Z时发送该信号
1 | # killall命令通过命令名终止进程: |
9.4 向用户终端发送消息
1 | # wall命令用来向当前所有登录用户的终端写入消息。 |
9.5 采集系统信息
1 | # 打印当前系统的主机名: |
9.6 使用 proc 采集信息
以Bash为例,它的进程ID是4295(pgrep bash),那么就会有一个对应的目录/proc/4295。进程对应的目录中包含了大量有关进程的信息。 /proc/PID中一些重要的文件如下所示。
environ:包含与进程相关的环境变量。使用cat /proc/4295/environ,可以显示所有传递给该进程的环境变量
cwd: 是一个到进程工作目录(working directory)的符号链接
exe:是一个到当前进程所对应的可执行文件的符号链接
$ readlink /proc/4295/exe
/bin/bashfd:包含了进程所使用的文件描述符
9.7 用 cron 进行调度
crontab任务配置基本格式:
1 | * * * * * command |
cron表中的每一个条目都由6部分组成,并按照下列顺序排列:
- 分钟(0~59)
- 小时(0~23)
- 天(1~31)
- 月份(1~12)
- 工作日(0~6)
- 命令(在指定时间执行的脚本或命令)
星号(*)指定命令应该在每个时间段执行。
除了数字还有几个个特殊的符号就是 "*"
、"/"
和 "-"
、","
,*
代表所有的取值范围内的数字,"/"
代表每的意思, "*/5"
表示每5个单位,"-"
代表从某个数字到某个数字, ","
分开几个离散的数字。以下举几个例子说明问题:
1 | # 指定每小时的第5分钟执行一次ls命令 |
配置用户定时任务的语法:
1 | $ crontab [-u user]file |
参数与说明:
- crontab -u //设定某个用户的cron服务
- crontab -l //列出某个用户cron服务的详细内容
- crontab -r //删除没个用户的cron服务
- crontab -e //编辑某个用户的cron服务
9.8 从终端截图
1 | # 取整个屏幕: |