基础
declare
declare 为 shell 解释器自建命令,默认所有变量类型均为字符串,脚本语言(解释器语言)是解释执行的,解释权归自己所有,只要语句自己认识即可,想咋定就咋定
declare(选项)(参数)
选项
-: 给变量设置类型属性
+: 取消变量的类型属性
-a:将变量声明为数组型
-i:将变量声明为整型
-x:将变量声明为环境变量
-r:将变量声明为只读变量
-p:查看变量的被声明的类型
参数
# 声明 x,y,z,默认字符串连接
[cmd] x=1
[cmd] declare -p x
declare -- x="1"
[cmd] y=1
[cmd] z=$x+$y && echo $z
1+1
[cmd] declare -i z
[cmd] declare -p z
declare -i z="1+1"
# 声明 i_z 整形,加法不再默认字符串连接
[cmd] declare -i i_z=$x+$y && echo $i_z
2
[cmd] declare -p i_z
declare -i i_z="2"
# 数组,不需要声明
[cmd] a_x1=1
[cmd] a_x2=2
[cmd] declare -p a_x
declare -a a_x='([0]="1" [1]="2")'
# 声明只读,可以只有声明,不赋值,不可修改,不可 -p
[cmd] declare -r r_x
[cmd] declare -p r_x
-bash: declare: r_x: not found
[cmd] declare -r x
[cmd] declare -p x
declare -r x="1"
[cmd] declare -r i_z
# i_z 整形只读,只读设置不可撤销
[cmd] declare -p i_z
declare -ir i_z="2"
[cmd] i_z=4
-bash: i_z: readonly variable
[cmd] declare +r i_z
-bash: declare: i_z: readonly variable
引号
特殊字符,有些字符在 shell 中具有特殊含义,需要转义处理,如下表
关键字,充当指令的字符,有些关键字使用特殊字符
单引号、双引号、无引号,在 shell 中,默认所有输入都为字符串,不需要任何引号,规定双引号跟无引号等同,加双引号是为了减少失误。shell 中这些特殊输入输出需要加反斜杠 \( 例如 \# 表示 #,\! 表示 ! )。若不加反斜杠,使用单引号也可达到同样效果
#, ;, ;;, . ., ., "", '', \, /, `, :, !, *, ?, $, (), {}, [], [[]], (()), >& >>& >> <, << <<<, \<, \>, |, >|, ||, &, &&, ~, !, ,, ^
POSIX 正则表达式规范
包括 BRE(基本型)和 ERE(扩展型)两类规则,互不兼容。BRE 规定关键字字符:., \, [, ^, $, * 。ERE中规定关键字字符多 7 个,(, ), {, }, +, ?, | 。grep、vi、sed 工具遵循 BRE 规范,grep -e, egrep, awk 工具遵循 ERE 规范。对于这些工具,会按照相应规范处理这些关键字符。其它没有被当作关键字的特殊字符,加反斜杠输入输出。
实例分析,查找字符串 xoo, grep ".o\{2\}" filename。这里 . 本来是特殊字符,这里 grep 选作关键字,\{ 和 \} 表示花括号, grep 将参数识别为 .o{2},如下是查找特殊字符的命令
[cmd]grep '\"' one.txt -on
[cmd]grep "\\\\\\\\" one.txt
[cmd]grep "'" one.txt -on
[cmd]grep "\\$" one.txt -on
[cmd]grep "|" one.txt -on
[cmd]grep "\\^" one.txt -on
[cmd]grep "\^" one.txt -on
[cmd]grep "#" one.txt -on
[cmd]grep ";" one.txt -on
[cmd]grep "." one.txt -on
[cmd]grep "\." one.txt -on
[cmd]grep "/" one.txt
[cmd]grep "\*" one.txt
[cmd]grep "\?" one.txt
[cmd]grep "\[" one.txt -on
[cmd]grep "\]" one.txt -on
[cmd]grep "<" one.txt -on
[cmd]grep ">" one.txt -on
[cmd]grep "||" one.txt -on
[cmd]grep "&" one.txt -on
[cmd]grep "&&" one.txt -on
[cmd]grep "~" one.txt -on
[cmd]grep "\!" one.txt -on
grep 命令
以行为单位查找匹配内容,包含查找内容的行
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
查找 .gz 压缩文件用 zgrep 命令,跟 grep 基本相同
OPTIONS:
-v:反选
-w: 单词匹配
-x: 整行匹配
-n:打印行号
-o:grep 默认会输出匹配的行,如果只想输出匹配的字符串,加该参数
-F: 不要使用正则匹配,直接匹配
-e PATTERN:可以有多个,例如 -e "ab" -e "cd",查找 ab 或者 cd,PATTERN 按照相关正则标准写
-f FILE:指定关键字文件,查找少量关键字用 -e PATTERN ,查找几百个呢,用文件比较好
最后是一个被查找的文件列表
sed
一般用于对文件进行格式化,默认不会修改源文件,通过读取文件流到缓冲区,对缓冲行执行相关操作以标准输出流的方式输出,在输出时,会输出源行和修改后行内容。加 -i 参数会直接修改源文件,加 -n 只输出操作后行内容,没操作不输出。
sed [-inV] '/行选择器/动作'
指令:
-i 直接修改源文件
-V 版本信息
动作:
a:追加,在当前行后添加一行或多行。当添加多行时,除最后一行外,每行末尾需要用“\”代表数据未完结;
c:行替换,用c后面的字符串替换原数据行。当替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结;
i:插入,在当前行前插入一行或多行。当插入多行时,除最后一行外,每行末尾需要用“\”代表数据未完结;
d:删除,删除指定的行;
P:打印,输出指定的行;
s:字符串替换,用一个字符串替换另一个字符串。格式为“行范围s/旧字串/新字串/g”(和Vim中的替换格式类似);
# 文件内容
[cmd]cat two.txt
11111111a
22222222b
33333333c
# 查找含字符串 222 行,并在其之前插入 hello word
[cmd]sed '/222/i hello word' two.txt
11111111a
hello word
22222222b
33333333c
# 查找含字符串 222 行,并在其之后插入 hello word
[cmd]sed '/222/a hello word' two.txt
11111111a
22222222b
hello word
33333333c
# 查找含字符串 222 行,并将改为 hello word 两行
[cmd]sed '/222/c hello \n word' two.txt
11111111a
hello
word
33333333c
# 查找含字符串 222 行,并将该行 b 字符替换为 $
[cmd]sed '/222/s/b/$/g' two.txt
11111111a
22222222$
33333333c
awk
一般用于编辑文件。awk '[BEGIN{ commands }] [pattern{ commands }] [END{ commands }]' filename 一个awk脚本通常由BEGIN, 通用语句块,END语句块组成,三部分都是可选的。 脚本通常是被单引号或双引号包住。awk 脚本类似与 js 脚本,功能强大
awk执行过程分析
第一步: 执行BEGIN { commands } 语句块中的语句
BEGIN语句块:在awk开始从输入输出流中读取行之前执行,在BEGIN语句块中执行如变量初始化,打印输出表头等操作。
第二步:从文件或标准输入中读取一行,然后执行 pattern{ commands }语句块。它逐行扫描文件,从第一行到最后一行重复这个过程,直到全部文件都被读取完毕。
pattern语句块:pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行。{ }类似一个循环体,会对文件中的每一行进行迭代,通常将变量初始化语句放在BEGIN语句块中,将打印结果等语句放在END语句块中。
第三步:当读至输入流末尾时,执行END { command }语句块
在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
内置变量
$0 整行
$1, $2 第一列,第二列
NF 最后一列变量
FS 分隔符字符
NR 当前行号
-F: 指定分隔符
-v: 指定或者修改内部变量
-v OFS="===": 输出分隔符
cat score.txt
Marry 2143 78 84 77
Jack 2321 66 78 45
Tom 2122 48 77 71
Mike 2537 87 97 95
Bob 2415 40 57 62
$ cat cal.awk
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
$ awk -f cal.awk score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
分组计数,多个分隔符
111111*****2222222|||||||3333333########444444444&&&&&&&&&55555555
awk -F '[*|#&]+' '{print $3}' 333
awk '{arr[$1]++} END{for(i in arr){print(i ": " arr[i])}}' two.txt
数据统计
样本抽取
shuf -n 1000 srcName > dstName 从 srcName 抽取 1000 行到 dstName。先对样本进行分析,编写相应处理程序,跑样本,得到预测结果后,再处理源数据
文件切割,防止源数据过大,内存溢出
split -l 1000 test.txt -d -a 3 test_
-l:按行分隔,每1000行切割test.txt文件
-d:添加数字后缀
-a:以3位数数字做尾数
test_:分割后的文件的前缀
去重
uniq -c 相同行数量,只能统计相邻行
排序
sort -n -r -t ':' -k 3
-n,用数值排序,而非字典序
-r,倒序
-t ':', 冒号作为分隔符
-k 3,分割后第 3 列
计数
wc -l