shell以及sed awk总结
1、描述shell程序的运行原理(可附带必要的图形说明);什么是shell
Linux系统的shell作为操作系统的外壳,为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。
shell是用户和Linux内核之间的接口程序,如果把Linux内核想象成一个球体的中心,shell就是围绕内核的外层。当从shell或其他程序向Linux传递命令时,内核会做出相应的反应。
shell是一个命令语言解释器,它拥有自己内建的shell命令集,shell也能被系统中其他应用程序所调用。用户在提示符下输入的命令都由shell先解释然后传给Linux核心。
有一些命令,比如改变工作目录命令cd,是包含在shell内部的。还有一些命令,例如拷贝命令cp和移动命令rm,是存在于文件系统中某个目录下的单独的程序。对用户而言,不必关心一个命令是建立在shell内部还是一个单独的程序。
shell首先检查命令是否是内部命令,若不是再检查是否是一个应用程序。然后shell在搜索路径里寻找这些应用程序(搜索路径就是一个能找到可执行程序的目录列表)。如果键入的命令不是一个内部命令并且在路径里没有找到这个可执行文件,将会显示一条错误信息。如果能够成功找到命令,该内部命令或应用程序将被分解为系统调用并传给Linux内核。
2、总结shell编程中所涉及到的所有知识点(如:变量、语法、命令状态等等等,要带图的哟);
变量:可变化的量,程序运行为进程后在内存中申请的有名字空间,可反复存储。又可以叫可命名的内存空间
变量有一下几种形式
本地变量:作用范围为当前shell进程;
环境变量:作用范围为当前shell进程及其子进程;
局部变量:作用范围为某个函数执行过程;一个shell脚本有一个进程,一个进程包含多个函数。
位置参数变量:在脚本中引用传递给脚本的参数;在函数中引用传递给函数的参数;
特殊变量:$?, $*, $@, $#, $$
变量说明:
$$
Shell本身的PID(ProcessID)
$!
Shell最后运行的后台Process的PID
$?
最后运行的命令的结束代码(返回值)
$-
使用Set命令设定的Flag一览
$*
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$#
添加到Shell的参数个数
$0
Shell本身的文件名
本地变量:
name=value
name: 变量名
=:赋值符号
value:值
变量名:只能包含数字、字母和下划线;且不能以数字开头;
引用变量:${name}, $name 变量名后的花括号可以省略
# name=kfc210
# echo "$name"
kfc210
变量引用:
弱引用: "", 内部的变量可以替换;
强引用:'',其内部变量不会被替换;
命令引用:`COMMAND`, $(COMMAND),引用命令的执行结果;
声明为整型:
declare -i name[=value]
let name=value
否则的话,默认都是存储成字符型
查看所有变量:set
SHELL 生命周期:从创建开始,到销毁结束
创建
销毁:
自动销毁:shell进程终止;
手动销毁:unset name
# echo "$name"
kfc210
# unset name
# echo "$name"
环境变量:作用域为当前进程和子进程
被“导出”的本地变量
export name[=value]
declare -x name[=value]
# name="kof210"
# export name
# echo $name
kof210
# bash
# echo $name
kof210
查看所有环境变量:env, printenv, export
条件测试:
界定程序执行环境;
(1) 根据运行的命令的状态结果;
(2) 测试表达式
test EXPRESSION
[ EXPRESSION ]
` EXPRESSION `
整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;
$A -gt $B:是否大于;是则为“真”,否则为“假”;
# a=3
# b=5
# [ $a -gt $b ]
# [ $a -gt $b ]
# echo $?
1
$A -ge $B: 是否大于等于;
$A -lt $B:是否小于;
$A -le $B: 是否小于等于;
$A -eq $B: 是否等于;
$A -ne $B:是否不等于;
字符串测试:ASCII数值越大,字符比较时其值越大;
"$A" > "$B":是否大于;
"$A" < "$B":是否小于;
"$A" == "$B":是否等于;
"$A" != "$B":是否不等于;
-z "$A":是否为空;空则为“真”,否则为“假”
-n "$A":是否不空;不空则“真”,空则为“假”
注意:应该使用` EXPRESSION `
文件测试:测试文件的存在性以及属性;
-e $file: 是否存在;存在则为“真”,否则为“假”;
-a $file: 同上;
-f $file:文件是否存在且为普通文件;
-d $file:文件是否存在且为目录;
# [ -d /etc ]
# echo $?
0
-h $file:是否存在且为符号链接文件;
-L $file: 同上
-b $file:是否存在且为块设备文件;
-c $file:是否存在且为字符设备文件;
-S $file:是否存在且为套接字文件;
-p $file: 是否存在且为管道文件;
-r $file: 当前用户对文件是否拥有读权限;
-w $file:当前用户对文件是否拥有写权限;
-x $file:当前用户对文件是否拥有执行权限;
-u $file:文件是否拥有SUID权限;
-g $file:文件是否拥有SGID权限;
-k $file:文件是否拥有sticky权限;
-O $file: 当前用户是否为指定文件的属主;
-G $file: 当前用户是否为指定文件的属组;
双目操作符:
$file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的;
$file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的;
$file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件的硬链接;
3、总结课程所讲的所有循环语句、条示例;(if (jpg|png is not exist);echo ”You say a XX“)
条件判断(选择执行):
if/then, case
if CONDITION; then
if-true-分支
fi
if CONDITION; then
if-true-分支
else
if-false-分支
fi
! CONDITION: 取反
练习:判断a和b是否相等
# cat a.sh
#!/bin/sh
a=1
b=2
if [ $a == $b ]
then
echo "a is equal to b"
fi
if [ $a != $b ]
then
echo "a is not equal to b"
fi
# bash a.sh
a is not equal to b
循环语句:
for, while, until
循环:将循环体代码执行0、1或多次;
进入条件:进入循环的条件;
退出条件:循环终止的条件;
for VARIABLE in LIST; do
循环体
done
LIST:是由一个或多个空格或换行符分隔开的字符串组成;
把列表的每个字符串逐个赋值给VARIABLE表示的变量;
for username in user1 user2 user3; do
循环体
done
进入条件:列表非空;
退出条件:列表遍历结束;
练习: 添加5个用户,user1-user5;
#!/bin/bash
#
for username in user1 user2 user3 user4 user5; do
if id $username &> /dev/null; then
echo "$username exists."
else
useradd $username
echo "Add user $username finished."
fi
done
# bash b.sh
Add user user1 finished.
Add user user2 finished.
Add user user3 finished.
Add user user4 finished.
Add user user5 finished.
case语句
简洁版多分支if语句;
使用场景:判断某变量的值是否为多种情形中的一种时使用;
语法:
case $VARIABLE in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
PATTERN3)
分支3
;;
...
*)
分支n
;;
esac
PATTERN可使用glob模式的通配符:
*: 任意长度的任意字符;
?: 任意单个字符;
[]: 指定范围内的任意单个字符;
a|b: 多选1;
示例:提示键入任意一个字符;判断其类型;
#!/bin/bash
#
read -p "Plz enter a character: " char
case $char in
)
echo "A character."
;;
)
echo "A digit."
;;
*)
echo "A special character."
;;
esac
# bash c.sh
Plz enter a character: 5
A digit.
流程控制:
循环语句:for, while, until
while循环:
while CONDTION; do
循环体
done
进入条件:当CONDITION为“真”;
退出条件:当CONDITION为“假”;
while CONDITION; do
循环体
控制变量的修正表达式
done
示例:求200以内所有正整数之和;
#!/bin/bash
#
declare -i sum=0
declare -i i=1
while [ $i -le 100 ]; do
let sum+=$i
let i++
done
echo "Sum: $sum."
# bash d.sh
Sum: 5050.
4、总结文本处理工具sed及awk的用法;(必须附带示例)
sed命令:
sed: stream editor, 流编辑器;
awk(gawk):文本格式化工具,报告生成器
sed命令:
基本正则表达式元字符:
字符匹配:., [], [^]
次数匹配:*, \?, \+, \{m,n\}, \{n\}
位置锚定:^, $, \
分组及引用:\(\), \1, \2, ...
多选一:a|b|c
vim编辑中文本的查找替换:
地址定界s/要查找的内容/替换为的内容/
要查找的内容:可使用正则表达式
替换为的内容:不支持正则表达式,但支持引用前面正则表达式分组中的内容
地址定界:%, startline,endline
语法:sed ... {script} ...
工作机制:每次读取一行文本至“模式空间(pattern space)”中,在模式空间中完成处理;将处理结果输出至标准输出设备;
-r: 支持扩展正则表达式;
-n: 静默模式;
-e script1 -e script2 -e script3:指定多脚本运行;
-f /path/to/script_file:从指定的文件中读取脚本并运行;
-i: 直接修改源文件;
地址定界:
#: 指定行;
$: 最后一行;
/regexp/:任何能够被regexp所匹配到的行;
\%regexp%:同上,只不过换作%为regexp边界符;
/regexp/| :
\%regexp%| :匹配时忽略字符大小写;
startline,endline:
#,/regexp/:从#行开始,到第一次被/regexp/所匹配到的行结束,中间的所有行;
#,#
/regexp1/,/regexp2/:从第一次被/regexp1/匹配到的行开始,到第一次被/regexp2/匹配到的行结束,中间的所有行;
#,+n:从#行开始,一直到向下的n行;
first~step:指定起始行,以及步长;
1~2,2~2
sed的编辑命令
d: 删除模式空间中的行;
=:显示行号;
a \text:附加text
i \text:插入text,支持\n实现多行插入;
c \text:用text替换匹配到的行;
p: 打印模式空间中的行;
s/regexp/replacement/:替换由regexp所匹配到的内容为replacement;
g: 全局替换;
w /path/to/somefile:把指定的内容另存至/path/to/somefile路径所指定的文件中;
r /path/from/somefile:在文件的指定位置插入另一个文件的所有内容,完成文件合并;
练习:
(1) 删除/etc/fstab文件中所有以#开头,后跟至少一个空白字符的行的行首的#和空白字符;
# sed 's/^#[[:space:]]\+//' /etc/fstab
#
/etc/fstab
Created by anaconda on Tue Sep1 17:44:05 2015
#
Accessible filesystems, by reference, are maintained under '/dev/disk'
See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=5db67257-2d08-411f-ac32-4f6cb67989a9 / xfs defaults 0 0
UUID=8f25f9e4-736f-45cc-bba9-4d1486cb0d7f /boot xfs defaults 0 0
UUID=86a4f4ba-2c9e-4ea2-94f3-27330220e711 /usr xfs defaults 0 0
UUID=0f6ebed3-5d29-4d69-ac1a-1ff46134f8e3 /var xfs defaults 0 0
UUID=9000a778-1e52-4229-96db-0410c38bbcaf swap swap defaults 0 0
UUID="bee9ad7a-7f48-4c23-bb61-ab34da08cf55" /mydata ext4 defaults
(2) 把/etc/fstab文件的奇数行另存为/tmp/fstab.3;
# sed '1~2w /tmp/fstab.3' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Tue Sep1 17:44:05 2015
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=5db67257-2d08-411f-ac32-4f6cb67989a9 / xfs defaults 0 0
UUID=8f25f9e4-736f-45cc-bba9-4d1486cb0d7f /boot xfs defaults 0 0
UUID=86a4f4ba-2c9e-4ea2-94f3-27330220e711 /usr xfs defaults 0 0
UUID=0f6ebed3-5d29-4d69-ac1a-1ff46134f8e3 /var xfs defaults 0 0
UUID=9000a778-1e52-4229-96db-0410c38bbcaf swap swap defaults 0 0
UUID="bee9ad7a-7f48-4c23-bb61-ab34da08cf55" /mydata ext4 defaults 0 0
# cat /tmp/fstab.3
# /etc/fstab
#
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=5db67257-2d08-411f-ac32-4f6cb67989a9 / xfs defaults 0 0
UUID=86a4f4ba-2c9e-4ea2-94f3-27330220e711 /usr xfs defaults 0 0
UUID=9000a778-1e52-4229-96db-0410c38bbcaf swap swap defaults
(3) echo一个文件路径给sed命令,取出其基名;进一步地,取出其路径名;
# echo "/etc/sysconfig/network-scripts/" | sed 's@^.*/\([^/]\+\)/\?$@\1@'
network-scripts #取基名
# echo "/etc/sysconfig/network-scripts/" | sed 's@[^/]\+/\?$@@'
/etc/sysconfig/ #取路径名
sed命令另一个称作"hold space"的内存空间:
高级命令:
h:用模式空间中的内容覆盖保持空间的内容;
H:把模式空间中的内容追加至保持空间中内容的后面;
g:从保持空间中取到其内容,并将其覆盖模式空间中的内容;
G:从保持空间中取到其内容,并将其追加在模式空间中的内容的后面;
x:把保持空间和模式空间中的进行交换;
n:读取匹配到的行的下一行至模式空间;(会覆盖模式空间中的原有内容);
N:读取匹配到的行的下一行至模式空间,追加在模式空间中原有内容的后面;
d:删除模式空间中的内容;
D:删除多行模式空间中的首行;
注意:命令功能可使用!取反;分号可用于分隔脚本;
示例:
sed 'G' /etc/issue: 在文件中的每行后方添加空白行;
sed '$!d' /etc/fstab:保留最后一行;
sed '/^$/d;G' /etc/issue: 保证指定的文件每一行后方有且只有一个空白行;
sed 'n;d' /etc/issue:保留奇数行;
sed -n '1!G;h;$p' /etc/issue
sed '$!N;$!D' /etc/issue
sed命令:
-e 'script' -e 'script'
'script;script;script'
script
script
script
-f /path/from/script
awk
基本语法
awk 'program' file file ...
awk 'PATTERN{action}' file file ...
-F CHAR:输入分隔符
1、awk的输出
print item1, item2,...
要点:
(1) 各项目之间使用逗号分隔,而输出时则使用输出分隔符分隔;
(2) 输出的各item可以字符串或数值、当前记录的字段、变量或awk的表达式;数值会被隐式转换为字符串后输出;
(3) print后面item如果省略,相当于print $0;输出空白,使用pirnt "";
2、awk的变量
内置变量,自定义变量
2.1 内置变量
FS:Field Seperator, 输入时的字段分隔符
# awk 'BEGIN{FS=":"}{print $1,$7}' /etc/passwd
RS:Record Seperator, 输入行分隔符
OFS: Output Field Seperator, 输出时的字段分隔符;
ORS: Outpput Row Seperator, 输出时的行分隔符;
NF:Numbers of Field,字段数
NR:Numbers of Record, 行数;所有文件的一并计数;
FNR:行数;各文件分别计数;
ARGV:数组,保存命令本身这个字符,awk '{print $0}' 1.txt 2.txt,意味着ARGV保存awk,
ARGC: 保存awk命令中参数的个数;
FILENAME: awk正在处理的当前文件的名称;
2.2 可自定义变量
-v var_name=VALUE
变量名区分字符大小写;
(1) 可以program中定义变量;
(2) 可以命令行中通过-v选项自定义变量;
3、awk的printf命令
命令的使用格式:printf format, item1, item2,...
要点:
(1) 要指定format;
(2) 不会自动换行;如需换行则需要给出\n
(3) format用于为后面的每个item指定其输出格式;
format格式的指示符都%开头,后跟一个字符:
%c: 显示字符的ASCII码;
%d, %i: 十进制整数;
%e, %E: 科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法格式或浮点数格式显示数值;
%s: 显示字符串;
%u: 显示无符号整数;
%%: 显示%自身;
修饰符:
#:显示宽度
-:左对齐
+:显示数值的符号
.#: 取值精度
4、awk输出重定向
print items > output-file
print items >> output-file
print items | command
特殊文件描述符:
/dev/stdin: 标准输入
/dev/stdout: 标准输出
/dev/stderr: 错误输出
5、awk的操作符
算术操作符:
x+y
x-y
x*y
x/y
x**y, x^y
x%y
-x:负值
+x:转换为数值
字符串操作符:连接
赋值操作符:
=
+=
-=
*=
/=
%=
^=
**=
++
--
如果模式自身是=号,要写为/=/
比较操作符:
<
>=
==
!=
~:模式匹配,左边的字符串能够被右边的模式所匹配为真,否则为假;
!~:
逻辑操作符:
&&: 与
||:或
条件表达式:
selector?if-true-expression:if-false-expression
# awk -F: '{$3>=1000?utype="common user":utype="admin or system user";print $1,"is",utype}' /etc/passwd
函数调用:
function_name(argu1,argu2)
6、模式
(1) Regexp: 格式为/PATTERN/
仅处理被/PATTERN/匹配到的行;
(2) Expression: 表达式,其结果为非0或非空字符串时满足条件;
仅处理满足条件的行;
(3) Ranges: 行范围,此前地址定界,
NR
仅处理范围内的行
(4) BEGIN/END: 特殊模式,仅在awk命令的program运行之前(BEGIN)或运行之后(END)执行一次;
(5) Empty:空模式,匹配任意行;
7、常用的action
(1) Expressions
(2) Control statements
(3) Compound statements
(4) input statements
(5) output statements
8、控制语句
8.1 if-else
格式:if (condition) {then body} else {else body}
# awk -F: '{if ($3>=500) {print $1,"is a common user"} else {print $1, "is an admin or system user"}}' /etc/passwd
# awk '{if (NF>=8) {print}}' /etc/inittab
8.2 while
格式:while (condition) {while body}
# awk '{i=1; while (i
页:
[1]