目录
Linux体系与编程复习
Linux的理念
-
小即是美
-
让程序员只做好一件事
-
可移植性比效率重要
-
一切即文件
-
使用Shell脚本来提高效率和可移植性
-
避免使用可定制性低下的用户界面
Linux系统结构
基本组成和体系结构
-
内核
-
shell
-
文件系统
-
应用程序
内核是硬件与软件之间的中间层
内核是一个资源管理程序
内核提供一组面向系统的命令
进程管理
-
进程是正在执行的一个程序或命令
-
进程有自己的地址空间,占用一定的系统资源
-
一个CPU核同一时间只能运行一个进程
-
进程由它的进程ID(PID)和它的父进程ID(PPID)唯一识别
查看进程信息
# 查看启动的nginx进程
ps -ef | grep nginx
# 查看某个进程
top -p 93824
#关闭指定的进程
kill 93824
# 全部进程动态实时视图
top
文件系统
Linux中一切皆文件
Linux文件系统是采用树状的目录结构,最上层是 /(根)目录
查看文件系统类型
fdisk -l # 查看磁盘分区信息
# df 命令报告文件系统磁盘空间利用率
df # -T 显示文件系统类型 | -a 显示所有文件系统 | -h人类可读格式
# mount 命令是挂载文件系统用的,不带任何参数运行,会打印包含文件系统类型在内的磁盘分区的信息
mount # -a 挂载所有文件系统 | -l 显示当前挂载 | -t 文件系统类型 | -o指定挂载权限
unount # 卸载
文件基本操作
ls # 查看文件夹下的内容
ls -l # 显示文件和目录权限
mkdir demo # 创建文件夹
mkdir -p /home/test/test_1.sh # mkdir会自动创建还不存在的父目录
mkdir -p -m 777 backup/new # -m可以设置你想要创建目录的权限
mv file file1 # 将源文件名file改为目标文件名file1
mv demo /home # 移动demo文件夹到 /home
rm test.txt # 删除文件test.txt
rm -r demo # 删除demo文件夹/目录
touch file.txt # 创建空文件
cp file.txt file_bak.txt # 复制文件
cp file.txt /tmp # 复制文件到目录下
ln -s f1.sh ln1 # 给文件f1.sh创建软连接,如果f1.sh丢失,ln1失效
ln f1.sh ln2 # 给文件f1.sh创建硬链接,f1.sh与ln2各项属性相同
文件读取流程
用户权限
用户账户
-
用户账户
普通用户账户:在系统中进行普通作业
超级用户账户:在系统中对普通用户和整个系统进行管理
-
用户组
标准组:可以容纳多个用户
私有组:只有用户自己
文件权限(关于用户)
-
所有者(Owner User):文件的所有者
-
所在组/用户组(Group):文件的所有者所在组
-
其他人(Others):除文件所有者及所在组外的其他人
每个用户对于文件都有不同的权限,包括读(R)、写(W)、执行(X)
查看用户信息
# 查看当前登录用户信息
w
# 查看当前用户所属的组
groups
# 查看用户uid的信息
id xxxx
用户权限操作
chmod [ugo][+-=][wrx] file # 修改权限
chmod 777 file # 赋予所有人读写执行权限 [4 读 2 写 1 执行]
# 在根目录创建一个文件夹,查看当前用户拥有文件夹的权限
cd / && mkdir demo && ls -ld demo
sudo useradd ceshi # 创建一个用户,并赋予可写操作
sudo passwd ceshi # 设置用户密码
su ceshi # 切换ceshi用户登录
cd demo # 进入demo文件夹
touch index.sh # 创建index.sh文件,提示没有权限,需要给ceshi用户demo文件夹的权限
sudo chmod o+r ./demo # demo文件夹写权限赋予其他人
su ceshi # 切换ceshi用户登录
cd demo # 进入demo文件夹
touch index.sh # 创建index.sh文件成功
Shell脚本和编程
Shell基础概念
构成
命令和语法
变量
类型 | 作用域 | 声明方式 | 规范 |
---|---|---|---|
自定义变量 | 当前shell | = | 字符串、整型、浮点型、日期型 |
环境变量 | 当前shell及其子shell | export、declare -x | |
系统环境变量 | 所有shell | 启动加载 |
自定义变量
# 变量名=变量值(等号左右不能有空格)
page_size=1
page_nunm=2
# 将命令复制给变量
_ls=ls
# 将命令结果赋值给变量
file_list=$(ls -a)
# 默认字符串,不会进行+运算
total=page_size*page_num(×)
# 声明变量为整型
let total=page_size*page_num
declare -i total=page_size*page_num
# 导出环境变量
export total
declare -x total
系统环境变量
变量名 | 含义 | 常见操作 |
---|---|---|
$0 | 当前shell名称/脚本名称 | $1、$2等可以获取到传入参数 |
$# | 传入脚本的参数数量 | if [ $# -gt 1 ] |
$* | 传入脚本的所有参数 | |
$? | 上条命令执行的状态码 | if [ $? -eq 0 ] |
$PS1 | 命令提示符 | export PS1="\u@\h\w>" |
$HOME | 用户主文件夹 | cd ~ |
$PATH | 全局命令的搜索路径 | PATH=$PATH:[新增路径] |
运算符和引用
类型 | 符号 | 作用 | 用法 |
---|---|---|---|
算数运算符 | + - * / % | & | 常规运算 | |
逻辑运算符 | || && ! | ||
比较运算符 | == ! = < > | ||
引号 | 双引号 "" | 部分引用,仅仅 $`\ 保留作用 | foo="${a}123" |
单引号 '' | 完全引用,原样输出 | foo='foo$a' | |
反引号`` | 执行命令 | foo='ls -a' | |
圆括号 | (()) | 算数运算 | foo=$((1+2)) |
() | 执行命令 | $(ls -a) | |
命令连接 | || | cmd1执行完且返回码非0,继续执行cmd2 | cmd1 || cmd2 |
&& | cmd1执行完且返回码非0,继续执行cmd2 | cmd1 && cmd2 | |
; | cmd1、cmd2串行执行 | cmd1 ; cmd2 | |
后台运行 | & | 让命令在后台运行,可与nohup一起使用 | cmd & |
Shell常用命令
命令 | 作用 |
---|---|
ls | 列出目录及文件名 |
cat | 连接显示文件内容 |
head | 显示文件头部 |
file | 查看文件类型 |
less、more命令 | 分屏显示文件 |
wc | 查看文件的统计信息 |
find | 查看文件或目录 |
cd | 切换目录 |
pwd | 显示目前的目录 |
mkdir | 创建新的目录 |
rmdir | 删除一个空的目录 |
cp | 复制文件或目录 |
rm | 删除文件或目录 |
mv | 移动文件与目录,或修改文件与目录的名称 |
常用具体命令
命令 | 作用 |
---|---|
ls -l | 列目录并以长格式显示文件信息 |
ls -lh | 列目录并以长格式显示文件信息,其中文件大小以符合人类阅读习惯的格式 |
ls -ld /home | 以长格式显示/home目录的信息 |
ls -la | 列目录并以长格式显示文件信息,-a表示显示所有文件,其中,包括以’.’开头的隐藏文件 |
ls -ltr | 列目录并以长格式显示文件信息,并将长列表格式按文件或目录的修改时间倒序地列出文件和目录 |
ls -ls | 显示文件/etc/group的文件内容 |
cat /etc/group | 显示文件/etc/group的文件内容 |
cat *he | 显示he开头的所有文件内容 |
cat *.sh | 显示sh结尾的所有文件内容 |
more /etc/group | 以翻页的方式查看文件/etc/group的内容 |
more -5 /etc/group | 以翻页的方式查看文件/etc/group的内容,每页大小为5行 |
more *.sh | 以翻页的方式查看以.sh结尾的所有文件内容 |
less /etc/group | 以翻页的方式查看文件/etc/group的内容 |
head -n 5 /etc/group | 查看文件/etc/group的前5行内容 |
tail -n 5 /etc/group | 显示文件/etc/group的最后5行内容 |
file /etc/group | 查看文件/etc/group的文件类型 |
wc /etc/group | 查看文件/etc/group的行数、单词数和字符数 |
wc -l /etc/group | 统计文件/etc/group的行数 [-w 单词数 | -c 字节数 | -L 最长的行的长度] |
ls | wc -l | 列出当前目录下的所有文件及目录并统计行数 |
ls -l | grep ^- | wc -l | 统计当前目录下的所有文件的数量 |
ls -l | grep ^d | wc -l | 统计当前目录下的所有目录的数量 |
find /etc -name group | 搜索目录/etc下是否存在group为文件名的文件 |
find / -type d -name etc | 根目录下查找目录名称为etc的目录 |
find / -type f -name "*.sh" | 根目录下查找文件名称以.sh结尾的所有文件 |
find / -type f -empty | 查找根目录下的所有空文件 |
find / -type d -empty | 查找根目录下的所有空目录 |
find / -type f -mitime +30 -mtime -60 | 查找根目录下,30天以前,60天以内的所有文件 |
文本处理
命令 | 作用 |
---|---|
sort | 文本排序,默认第一列以ASCII码排列,-n 从小到大 | -r 从大到小 | -t 按列排序 |
uniq | 文本去重 ,-c 每行行首统计重复行重复次数 | -u 只显示不重复的行 | -d 显示所有重复的行 |
tr | 替换或删除字符 | -d 删除字符 |
tr [:lower:][:upper:] | 小写转大写; 或者tr a-z A-Z |
grep | 查找字符串 grep hello file | -v 打印出不符合条件行的内容 |
diff | 比较两个文件 |
date命令
date +"%Y-%m-%d" # 显示年月日时间
date +%s # 获取时间戳
标准输入
read 从标准输入读取数值
-
-p 后面跟提示信息,即在输入前打印提示信息。
-
-n 后跟一个数字,定义输入文本的长度,很实用。
-
-r 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。
-
-s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。
-
-t 后面跟秒数,定义输入字符的等待时间。
*参数扩展
参数扩展就是通过符号$获得参数中存储的值
基本的参数扩展
$param 或者 ${param}
word=car
echo ${word}s
=>cars
间接参数扩展
${!param} 将参数扩展为参数变量的值
a=b
b=123
echo ${a} #基本扩展,输出结果为b
echo ${!a} #间接参数扩展,输出结果为123
大小写修改
a=hello
b=HELLO
echo ${a^} # 将a中第一个小写字母变成大写 Hello
echo ${a^^} # 将a中所有小写字母变成大写 HELLO
echo ${b,} # 将变量b中的第一个大写字母为小写 hELLO
echo ${b,,} # 将b中所有大写字母变成小写 hello
变量名扩展
${!PREFIX*} / ${!PREFIX@} 列出以字符串PREFIX开头的所有变量名
字符串移除
掐头去尾:${var#分隔符} ${var##分隔符} ${var%分隔符} ${var%%分隔符}
-
操作符‘#’和‘%’表示将移除匹配指定模式的最短文本
-
操作符‘##’和‘%%’表示移除匹配指定模式的最长文本
# 掐头
a=123:457:789:1245:456
echo ${a#*:} # 以:为分隔符进行最短掐头 457:789:1245:456
echo ${a##*:} # 以:为分隔符进行最长掐头 456
# 去尾
echo ${a%:*} # 以:为分隔符进行最短去尾 123:457:789:1245
echo ${a%%:*} # 以:为分隔符进行最长去尾 123
字符串搜索和替换
${var/被替换字串/替换字串}
${var//被替换字串/替换字串}
-
操作符‘/’表示只替换一个匹配的字符串
-
操作符‘//’表示替换所有匹配的字符串
a="this is s test"
echo ${a}
echo ${a/is/mm} #最短替换,替换匹配的第一个is
echo ${a//is/mm} #最长替换,替换所有匹配的is
# 替换字串为空,删除操作
a="this is s test"
echo ${a}
echo ${a/is/} #删除匹配的第一个is
echo ${a//is/} #删除匹配的所有is
字符串长度
${#param} 此参数扩展可以得到参数值的长度
$ MYSTRING="Hello World"
$ echo ${#MYSTRING}
11
子字符串
${var:开始:长度}
${PARAMETER:OFFSET}** # 从offset到末尾
${PARAMETER:OFFSET:LENGTH}
使用默认值
${PARAMETER:-WORD} ${PARAMETER-WORD}
a="" #定义一个null变量a,引号之间没有内容即是一个null
echo ${a}
echo ${a:-hello} #此时变量a为null,hello将临时赋予变量a
echo ${a-hello} #a已定义为null,不做任何操作
a="hello" #当变量定义且不为null时,${a:-world}和${a-world}不做任何操作
echo ${a}
echo ${a:-world}
echo ${a-world}
echo ${b} #变量b未定义时,${b:-hello}和${b-hello}都会将hello临时赋予b
echo ${b:-hello}
echo ${b-hello}
默认值赋值
${var:=默认值} / ${var=默认值} 两种方法效果一样
a="" #变量a被定义为null
echo ${a}
echo ${a:=hello} #由于变量a为null,hello被赋予a,作为a的默认值
echo ${a}
a="hello"
echo ${a}
echo ${a:=world} #a被定义且不为null,此时不做任何扩展
echo ${a}
echo ${c}
echo ${c:=hello} #变量c未被定义,hello被赋予c的默认值
echo ${c}
使用代替值
${var:+替代值} ${var+替代值} 两种方法效果一样
a=""
echo ${a}
echo ${a:+hello} #a被定义为null,此时不做任何扩展
echo ${d}
echo ${d:+hello} #b未被定义,此时也不做任何扩展
a="hello"
echo ${a}
echo ${a:+world} #当a被定义且不为null时,a被扩展为替代值
检查变量是否未定义或被定义为null
a=""
echo ${a}
echo ${a:?error} #a被定义为null,此时将输出:-bash: a: 提示值
echo ${d}
echo ${d:?error} #d未定义,此时将输出:-bash: d: 提示值
a="hello"
echo ${a}
echo ${a:?error} #a已定义且不为null,此时不做任何扩展
管道
管道与管道符 |, 作用是将前一个命令的结果传递给后面的命令
cmd1 | cmd2
重定向
输出重定向符号
>: 覆盖写入文件
>>: 追加写入文件
2>: 错误输出写入文件
&>: 正确和错误输出统一写入到文件中
输入重定向符号
<
<<
判断命令
shell中提供了test、[ ] 、[[ ]] 三种判断符号, 可用于:
-
整数测试
-
字符串测试
-
文件测试
语法:
-
test condition
-
[ condition ]
-
[[ condition ]]
注意:
-
中括号前后要有空格符
-
[ 和 test 是命令, 只能使用自己支持的标志位, <、>、= 只能用来比较字符串
-
[[ 更丰富, 在整形比较中支持<、>、=,在字符串比较中支持=~正则
分支语句
# 语法1
if condition; then
程序段
elif condition; then
程序段
else
程序段
fi
# 语法2
case $变量 in:
"变量")
程序段
;;
"变量")
程序段
;;
*)
程序段
;;
esac
循环
-
while循环
while condition; do 程序段 done
例子:计算1~100内所有奇数之和
sum=0
i=1
while(( i <= 100 ))
do
let "sum+=i"
let "i += 2"
done
echo "sum=$sum"
-
until循环
until condition; do 程序段 done
例子:计算1~100内所有奇数之和
i=1
sum=0
until [[ "$i" -gt 100 ]] #直到i大于100
do
let "sum+=i"
let "i += 2"
done
echo "sum=$sum"
-
for循环
# 基本语法 for var in [words...]; do 程序段 done # 表达式语法 for (( EXP1; EXP2; EXP3 )) do 程序段 done
例子:计算1~100内所有奇数之和
sum=0
for i in {1...100...2}
do
let "sum+=i"
done
echo "sum=$sum"
循环控制
-
break:退出本层循环循环。
-
continue:只退出本次循环,仍然执行后继续循环。
函数
-
语法一:
funcName(){ echo "abc"; }
-
语法二:
function funcName(){ echo "abc"; }
注意:
-
shell自上而下执行,函数必须在使用前定义
-
函数获取变量和shell script类似,$0代表函数名,后续参数通过$1、$2...获取
-
函数内return仅仅表示函数执行状态,不代表函数执行结果
-
返回结果一般使用echo、printf,在外面使用$()、``获取结果
-
如果没有return,函数状态是上一条命令的执行状态,存储在$?中
-
$# 传递到脚本或函数的参数个数
正则表达式
* (星号) | 前一个字符匹配0次或者任意多次 | "a" 匹配所有内容,包括空白行 "aa" 匹配至少包含一个a的行 "aaa" 匹配最后包含两个连续a的字符串 "aaaaa"匹配最少包含4个连续a的字符串 |
---|---|---|
.(句点) | 匹配除了换行符外的任意一个字符 | "s..d" 匹配在s和d这两个字母之间一定有两个字符的单词 "s.d" 匹配在s和d字母之间有任意字符 "." 匹配所有内容 |
^(插入) | 匹配行首 | "^hello" 匹配以hello开头的行 "^M" 匹配以大写“M”开头的行 |
$(美元符) | 匹配行尾 | "hello$" 匹配以hello结尾的行 "n$" 匹配以小写“n”结尾的行 "^$" 匹配空白行 |
[ ](方括号) | 匹配中括号中指定的任意一个字符,只匹配一 个字符 | "[aeiou]" 匹配任意一个元音字母, "[0-9]" 匹配任意一位数字, "a-z" 匹配小写字母和一位数字构成的两位字符。 "s[ao]id" 匹配s和i字母中,要么是a,要么是o"[0-9]" 匹配任意一个数字"^[a-z]" 匹配小写字母开头的行 |
[^] | 匹配中括号的字符以外的任意一个字符 | "0-9" 匹配任意一位非数字字符, "a-z" 表示任意一位非小写字母 "^a-z" 匹配不是小写字母开头的行 "^a-zA-Z" 匹配不是字母开头的行 |
\(反斜线) | 转义符。用于将特殊符号的含义取消 | ".$" 匹配使用"."结尾的行 |
{n} | 表示其前面的字符恰好出现n次 | "[0-9]{4}" 匹配4位数字, "1[0-9]{9}" 匹配手机号码 "a{3}" 匹配a字母连续出现3次的字符串 "[0-9]{3}" 匹配包含连续的3个数字的字符串 |
{n,} | 表示其前面的字符出现不小于n次 | "[0-9]{2,}" 表示两位及以上的数字。 "[0-9]{3,}[a-z]" 匹配最少用连续3个数字开头的字符串 |
{n,m} | 表示其前面的字符至少出现n次,最多出现 m次 | "[a-z]{6,8}" 匹配6到8位的小写字母。 "sa{1,3}i" 匹配在字母s和i直接有最少一个a,最多三个a |
+ | 重复一个或者一个以上的前一个字符 | |
? | 零个或者一个的前一个字符 | |
| | 零个或者一个的前一个字符 | |
() | 查找“组”字符串 | |
()+ | 辨别多个重复的组 |
执行过程和原理
执行
-
shell脚本一般以 .sh 结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
#! /bin/bash #! /usr/bin/env bash
-
启动方式
# 文件名运行
./filename.sh
# 解释器运行
bash ./filename.sh
# source 运行
source ./filename.sh
执行过程
-
字符解析
-
识别换行符、分号(;)做行的分割
-
识别命令链接符(|| && 管道)做命令的分割
-
识别空格、tab符,做命令和参数的分割
-
shell展开,例如{1..3}解析为1 2 3
-
重定向,将stdin、stdout、stderr文件描述符进行指向变更
-
执行命令
-
builtin直接执行
-
非builtin使用$PATH查找,然后启动子进程执行
-
收集状态并返回
shell展开
大括号展开 {...}
一般由三部分构成,前缀、一对大括号、后缀、大括号内可以是逗号分割的字符串序列,也可以是序列表达式 {x..y[..incr]}
# 字符串序列
a{b,c,d}e => abe ace ade
# 表达式序列,(数字可以使用incr调整增量,字母不行)
{1..5} => 1 2 3 4 5
{1..5..2} => 1 3 5
{a..e} => a b c d e
波浪号展开 ~
# 当前用户主目录 ~ => $HOME ~/foo => $HOME/foo # 指定用户主目录 ~fred/foo => 用户fred的$HOME/foo # 当前工作目录 ~+/foo => $PWD/foo # 上一个工作目录 ~-/foo => ${$OLDPWD-'~-'}/foo
参数展开 ${}
-
间接参数扩展 ${!parameter},其中引用的参数并不是parameter而是parameter的实际值
-
参数长度 ${#parameter}
-
空参数处理
-
${parameter:-word} # 为空替换
-
${parameter:=word} # 为空替换,并将值赋给$parameter变量
-
${parameter:?word} # 为空报错
-
${parameter:+word} # 不为空替换
-
-
参数切片
-
${parameter:offset}
-
${parameter:offset:length}
-
-
参数部分删除
-
${parameter%word} # 最小限度从后面截取word
-
${parameter%%word} # 最大限度从后面截取word
-
${parameter#word} # 最小限度从前面截取word
-
${parameter##word} # 最大限度从前面截取word
-
命令替换
在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:$(...) 或 `...
`
例子:
#! /bin/bash
echo $(whoimi)
foo(){
echo "asdasd"
}
a=`foo`
数学计算 $((..))
使用$(())包裹数学运算表达式。得到结果并替换
#! /bin/bash
echo $((1+2)) # 3
文件名展开 * ? [..] 外壳文件名模式匹配
当有单词没有被引号包裹,且其中出现了 '*','?',and '[' 字符,则shell会按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变。
#! /bin/bash
$ echo D*
# 输出当前目录下所有以D字母开头的目录、文件
实验一:文件和目录操作
-
pwd : 显示当前工作目录
-
cd /:切换当前工作目录;从当前目录切换至根目录下
-
cd /home:切换当前工作目录;从当前根目录切换至home下
-
cd ..:返回上一级目录;即返回至home目录下
-
cd /etc:切换当前工作目录;从当前根目录切换至/etc目录下
-
man ls: 查看ls命令的使用说明
-
ls -l: 列目录并以长格式显示文件信息
-
ls -lh:列目录并以长格式显示文件信息,其中文件大小以符合人类阅读习惯的格式
-
ls -ld /home : 以长格式显示/home目录的信息
-
ls -la : 列目录并以长格式显示文件信息,-a表示显示所有文件,其中,包括以’.’开头的隐藏文件
-
ls -ltr:列目录并以长格式显示文件信息,并将长列表格式按文件或目录的修改时间倒序地列出文件和目录
-
ls -ls: 列目录并以长格式显示文件信息,并按文件大小顺序列出文件和目录
-
cat /etc/group:显示文件/etc/group的文件内容
-
cat *he: 显示he开头的所有文件内容
-
cat *.sh: 显示sh结尾的所有文件内容
-
more /etc/group: 以翻页的方式查看文件/etc/group的内容
-
more -5 /etc/group:以翻页的方式查看文件/etc/group的内容,每页大小为5行
-
more *.sh: 以翻页的方式查看以.sh结尾的所有文件内容
-
less /etc/group: 以翻页的方式查看文件/etc/group的内容
-
head -n 5 /etc/group: 查看文件/etc/group的前5行内容
-
tail -n 5 /etc/group: 显示文件/etc/group的最后5行内容
-
tail -f -n 5 /etc/group: 实时监控显示文件/etc/group的最后5行内容
-
file /etc/group:查看文件/etc/group的文件类型
-
wc /etc/group: 查看文件/etc/group的行数、单词数和字符数
-
wc -l /etc/group: 统计文件/etc/group的行数
-
ls | wc -l: 列出当前目录下的所有文件及目录并统计行数
-
find /etc -name group: 搜索目录/etc下是否存在group为文件名的文件
-
find / -type d -name etc:根目录下查找目录名称为etc的目录
-
find / -type f -name “*.sh”: 根目录下查找文件名称以.sh结尾的所有文件
-
find / -type f -empty:查找根目录下的所有空文件
-
find / -type d -empty: 查找根目录下的所有空目录
-
find / -type f -mtime +30 -mtime -60:查找根目录下,30天以前,60天以内的所有文件
-
touch /home/file1: home目录下创建一个文件名为file1的空文件
-
touch -a /home/file1: 更新文件file1的访问时间
-
touch -c -t 1212131030 /home/file1: 将文件file1的修改时间和访问时间设置为12年12月13日10点30分
-
mkdir /home/data: home目录下创建data目录
-
mkdir -p /home/data/text/word:-p表示创建多级目录,即在home/data目录下创建text目录,在home/data/text目录下创建word目录
-
cp /home/file1 /tmp: 复制home目录下file1文件到tmp目录下
-
rm /home/file1: 删除文件file1
-
rm /home/data -r: 删除目录data
-
su root: 切换到root用户
-
useradd -d /home/user1 -m user1: 新用户创建和新用户的主目录设置
-
passwd user1: 新用户登录密码设置
-
groupadd group1:创建用户组group1
-
usermod -a -G group1 user1:添加用户user1的用户组group1
-
groups:查看当前用户的用户组
-
Groups user1:查看用户user1的用户组
-
chmod g-w example.sh:移除文件example.sh用户组成员的写权限
-
chmod o+x example.sh:添加文件example.sh其他用户的写权限
-
chmod u=x example.sh: 只给文件example.sh的所有者执行权限
-
chmod ugo+rwx example.sh:赋予所有人对文件example.sh读、写、执行权限
-
chmod 777 file.sh:赋予所有人对文件file.sh读、写、执行权限
-
chmod 664 file.sh:赋予文件的所有者和用户组成员读写权限、其他用户只读权限
实验二:文本处理、归档与后台执行命令
练习sort、uniq、tr、grep、diff、tar等命令、理解每个命令功能和显示信息的意义
-
sort file1: 将文件file1的内容按照字母顺序排序
-
sort -n file1:按照数值的大小排序对文件file1的内容进行排序
-
sort -n -r file1:按照数值的大小排序对文件file1的内容进行排序,并按照倒序的方式进行显示
-
sort -t ‘,’ -k2 file1:按照第二列的字符串顺序将文件内容排序,-t选项用于指定的分隔符,此命令中的列分隔符是逗号“,”;-k选项用于指定进行排序的列
-
uniq file1: 移除重复行,只显示单一行
-
uniq -c file1: 移除重复行,并统计重复行次数
-
echo linux | tr a-z A-Z:将linux转换成大写
-
grep -r beifang /test/:递归搜索test目录下的所有文件,是否存在文件内容包含beifang
-
diff file1 file2: 比较文件file1与文件file2内容之间的差异
-
date +"%s":获取时间戳
-
date +"%Y-%m-%d":显示年月日时间
-
tar -cvf file.tar /home/test:对test目录进行归档不压缩
-
tar -zcvf file.tar.gz /home/test:对/home/test目录进行归档并压缩
-
tar -xvf file.tar:对归档文件file.tar进行解压
-
tar -zxvf /home/file.tar.gz:对压缩文件file.tar.gz进行解压
-
tar -tvf /home/file.tar:列出文件file.tar的内容,不进行解压
-
tar -tzvf /home/file.tar.gz: 列出文件file.tar.gz的内容,不进行解压
练习mount、df、du等命令、理解每个命令功能和显示信息的意义
-
df -h: 查看磁盘分区与挂载信息
-
fdisk -l: 查看磁盘信息
-
fdisk进行磁盘分区添加,mkfs 进行分区格式化、mount命令进行文件系统挂载
-
df:显示文件系统磁盘可用空间信息
-
df -h: 可读的格式显示磁盘可用空间信息
-
du /home: 显示home目录的所有目录大小,且以1024字节为大小单位
-
du -h /home: 以可读的格式显示home目录的所有目录大小
-
du -a /home: 以递归方式显示home目录的所有目录和文件的大小
-
du -ah /home: 以递归方式显示home目录的所有目录和文件大小,且大小为可读格式
利用crontab、nohup、&等命令完成指定任务
-
新建crontab任务每隔一分钟输出一条文本内容“crontab is running-当前时间”,并写入文件/home/crontab.txt
vim crontab.txt
echo $(date +"%Y-%m-%d") >> /home/lbl/crontab/$date +%Y-%m-%d
crontab -e
*/1 * * * * echo “crontab is running-” >> /home/lbl/crontab.txt
-
新建crontab任务每天的早上凌晨6点和12点执行任务,输出一条文本内容“hello”,并写入文件/home/crontab.txt
vim crontab.txt
echo “hello”
crontab -e
0 6,12 * * * /home/crontab.txt
-
新建crontab任务每隔5分钟生成一个文件,文件名称为ff,文件生成的目录为home
vim crontab.txt
touch ff
crontab -e
5 * * * * /home
-
/home下新建一个脚本gen-file.sh,脚本完成功能为每隔30秒钟生成一个文件,文件的名称为fff,生成目录为/home/data,使用nohup与&对此脚本进行后台运行
vim gen-file.sh
touch /home/data/fff
crontab -e
* * * * * sleep 30; touch /home/data/gen-file.sh
实验三:Shell脚本编程基础以及条件执行
练习字母大小写更改参数扩展方式、字符串移除的参数扩展方式、字符串替换的参数扩展方式.
-
使用字母大小写更改参数扩展方式编写脚本实现当前目录下的所有后缀为txt的文件的文件名转换为小写
for file in *.txt; do mv "$file" "${file,,}"; done
-
使用字母大小写更改参数扩展方式编写脚本实现当前目录下的所有后缀为txt的文件的文件名转换为大写
for file in *.txt; do mv "$file" "${file^^}"; done
-
使用字符串移除的参数扩展方式分别实现移除FILENAME=linux_bash.txt的文件名的后缀、移除文件名并保留后缀
移除文件后缀:echo ${ FILENAME%.* }
移除文件名并保留后缀:echo ${ FILENAME##*. }
-
使用字符串移除的参数扩展方式分别实现移除FILENAME=/home/yantaol/linux_bash.txt文件名并保留目录名、移除目录名并保留文件名
移除文件名保留目录名:echo ${FILENAME/linux_bash.txt}
移除目录名保留文件名:echo ${FILENAME//home/yantaol/}
-
使用字符串替换的参数扩展方式实现MYSTRING=“This is used for replacing string or removing string”中所有string替换为characters
字符串替换:echo ${MYSTRING//string/characters}
以下算术运算的结果是什么
-
let var=5**2
echo $var
结果:25
-
var=1
let var+=10
echo $var
结果:11
-
echo $((2 && 3))
结果:1
-
echo $((2 || 0))
结果:1
-
let var=(2+3, 10-5,20-6)
echo $var
结果:14
-
let var=32#20
echo $var
结果:64
-
expr 1 < 2
结果:1
-
expr 6+8
结果:6+8
利用test命令写出对应的条件
-
比较第一个数3是否大于第二个数,如果大于,则打印Ture,否则打印False
num1=1
num2=2
num3=3
if test $num3 > $num2
then
echo 'True'
else
echo 'False'
fi
-
检查文件/bin/cp是否存在,如果存在则打印找到此文件,否则打印没找到此文件
cd /bin
if test -e cp
then
echo '找到此文件'
else
echo '没找到此文件'
fi
-
测试字符串“abc”与”cde”是否相同,以及是否不相同。
test "abc" = "cde"; echo $?
test "abc" = "cde"; echo $?
-
比较5是否小于10,如果是,打印YES,否则打印NO
test 5 -lt 10 && echo YES || echo NO
练习条件执行语句
-
编写一脚本,接收用户输入一个参数,该参数值为1:打印install software,2:打印reload software,3:打印uninstall software
-
写一脚本,接收三个参数输入,打印出最大值
#! /bin/bash
read -p "input three numbers:" n1 n2 n3
max=$n1
if ((n2>max));then
max=$n2
fi
if ((n3>max));then
max=$n3
fi
echo "max=$max"
-
从键盘任意输入两个数,并进行四则运算
#!/bin/bash
echo "输入两个数"
read a b
echo "选择一种运算 1加 2减 3乘 4除"
read c
case "$c" in
1)
let sum=$a+$b;;
2)
let sum=$a-$b;;
3)
let sum=$a*$b;;
4)
let sum=$a/$b;;
esac
echo "$sum"
实验四:条件判断、循环控制与函数
练习if…else,以及case结构
-
编写脚本,检测是否存在目录/home/yantaol,如果不存在,则创建,如果存在则输出“The directory is exist”.
-
编写脚本,检测是否存在文件/etc/resolv.conf,如果存在则输出The file is exist,否则创建此文件
-
编写脚本,如果当前时间为Mon或者Sat,输出Please run full backup,如果当前时间是Tue,Web,Thu,Fri,输出please run incremental backup,如果当前时间是“Sun”,输出Do not need to backup,如果不是以上情况,则输出“Wrong day”,使用case语句实现
-
2.1 使用for循环编写shell脚本,判断/etc/yp.conf、/etc/nsswitch.conf、/etc/auto.master、/etc/resolv.conf是否存在这四个文件,如存在,则打印输出“The file 文件名 was found”,否则输出“* Error: The file 文件名 was missing. *”
-
使用for循环编写shell脚本,该脚本每行输出六个,之间以空格隔开,一共输出3行。
* * * * * *
* * * * * *
* * * * * *
for(( i=0;i<3;i++ ))
do
for(( j=0;j<5;j++ ))
do
echo -n "* "
done
echo " "
done
-
使用for循环编写shell脚本,该脚本打印This is used for replacing string or removing string”中单词字母数大于5的单词
-
使用while循环编写脚本,该脚本读取文件/etc/passwd,并打印出/etc/passwd中的每一行
while read text
do
echo $test
done < /etc/passwd
-
使用for与break编写一脚本,接收输入参数match,遍历etc下的所有文件,如果文件的路径与match相匹配,则打印“The file $match was found!”,并退出for循环
-
2.7 使用continue编写一脚本,遍历当前目录下的所有文件,如果文件名包含大写字母,则转换成小写,并输出转换前的文件名和转换后的文件名,如果文件名不包含大写字母,则直接跳过
#!/bin/bash
cd $1
for filename in 'ls'
do
if [ $filename != *[[:upper:]]* ]
then
continue
fi
new='echo $filename | tr 'A-Z' 'a-z''
mv $filename $new
echo "$filename $new"
done
练习函数创建以及函数的调用
-
编写脚本,定义一个函数,计算输入的所有参数的和
#!/bin/bash
function sum() {
total=0
for sum in "$@"
do
((total+=sum))
done
echo "total=$total"
}
sum 10 20 30
*实验五:正则表达式
练习正则表达式的元字符:星*、句点、插入符号^、美元符号$、方括号[]等使用方式,以及扩展正则表达式的元字符?、加号+、圆括号()、竖线|等使用方式
-
编写shell脚本,输入参数digit,判断此参数值是否匹配数字0~9中的任何一个数字,如果匹配,则输出$digit is a digit,否则输出Oops!
read digit
if [[ "$digit" =~ [0-9] ]]
then
echo "$digit is a digit"
else
echo 'Oops!'
fi
-
编写shell脚本,输入参数num,判断此参数值是否为一串数值,如果是,则输出It’s a number,否则输出It’s not a number
read num
if [[ "$num" =~ ^[0-9]+$ ]]
then
echo "It's a number"
else
echo "It's not a number"
fi
-
编写shell脚本,输入参数email,判断此参数值是否为一个邮箱地址,如果是,则输出This email address looks fine: $email,否则输出no
read email
if [[ "$email" =~ ^.*@.*\.[a-z,A-Z]*$ ]]
then
echo "This email address looks fine: $email"
else
echo "no"
fi
-
编写shell脚本,输入参数ip,判断此参数值是否为一个IPv4的地址格式,如果是,则输出Looks like an IPv4 IP address,否则输出Oops!
read ip
if [[ "$ip" =~ ^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$ ]]
then
echo "Looks like an IPv4 IP address"
else
echo "Oops!"
fi
-
使用grep和正则表达式,搜索文件/etc/passwd中以root开头的行
grep ^root /etc/passwd
-
使用grep和正则表达式,搜索文件/etc/passwd中以bash结尾的行
grep bash$ /etc/passwd
创建文件list.txt,并完成相应操作。
list.txt的内容如下:
1122
112
11222
Adb
Kkk
Akfcb
akfcb
Jgc
11 567
-
使用grep和正则表达式,搜索list.txt文件中,包含字符串“112”且其后至少有一个字符的行;
cat ./list.txt | grep "112*$"
-
使用grep和正则表达式,搜索list.txt文件中,字符A和b中间有一个任意字符的行
grep "A.b" list.txt
-
使用grep和正则表达式,查找字符2后面有两个任意字符的行
grep "2.." list.txt
-
使用grep和正则表达式,搜索文件list.txt中以11开头的所有行
grep "^11" list.txt
-
使用grep和正则表达式,搜索文件list.txt中以A开头b结尾的行
grep "^A.*b$" list.txt
-
使用grep和正则表达式,搜索文件list.txt中5个连续小写字母的行
grep "[a-z]\{5\}" list.txt
-
使用grep和正则表达式,搜索文件list.txt中包含字母A或字母b的行
grep "[Ab]" list.txt
-
使用grep和正则表达式,多种方式实现搜索文件list.txt中11 567的行
grep "11^.*567$" list.txt
grep "11\s\+567" list.txt
grep "11[[:space:]]\+567" list.txt
grep "11[ \t]+567" list.txt
实验六:脚本输入处理
练习使用case、shift、for循环等方式来处理命令行参数,以及能够测试命令行参数
-
编写shell脚本,该脚本接收一个输入参数,输入参数的值为start、stop、restart,status。当输入参数值为start时,打印出Starting the shell,当输入参数值为stop时,打印出Shutting down the shell,当输入参数值为restart时,打印出Shutting down the shell,Starting the shell,当输入参数为status时,打印出The shell is running,并编写一个usage函数,该函数打印出该脚本的参数用法
#! /bin/bash
read temp
case $temp in
start)
echo "Starting the shell"
;;
stop)
echo "Shutting down the shell"
;;
restart)
echo "Shutting down the shell,Starting the shell"
;;
status)
echo "The shell is running"
;;
*)
echo "please input again"
;;
esac
usage() {
echo "Usage: $0 <start|stop|restart|status>"
}
-
编写shell脚本,该脚本接收7个输入参数,分别使用shift和for循环遍历出输入的7个参数的值,并打印出每个参数的值
#!/bin/bash
while [ $# -ne 0 ]
do
echo “第一个参数为:$1 参数个数为:$#”
shift
done
-
编写shell脚本,该脚本只接收一个参数,该脚本需要检测参数个数是否为1,如果参数个数不为1,以状态码2退出脚本,并输出“Usage:param error”,以及检测参数的值是否为一个文件,如果是一个文件,输出“The file exist”, “如果不是一个文件,则输出“The param file does not exist”,并以状态码3退出脚本.
ARGS=1
if [ $# -ne "$ARGS" ]
then
echo "Usage: param error"
exit 2
fi
varStr=$1
if [ -f "$1" ]
then
echo "The file exist"
else
echo "The param file does not exist"
exit 3
fi
编写shell脚本,该脚本接收一个命令行选项(-e或者-p)以及一个文件参数,使用case进行处理。该脚本需要实现如下功能:
1)实现一个checkfile函数,该函数判断该文件参数的值是否存在,如果不存在输出“File name missing”并以状态码1退出,如果存在则接着进行判断文件参数对应的文件是否存在,如果不存在,则输出“The file does not exist!”,并以状态2退出
2)利用case处理选项,-e选项调用checkfile函数,并打印出“Edit file”。-p选项调用checkfile函数,并打印出“Displaying file”
3)如果未与-e或者-p匹配,则输出“Bad argument”,Usage:$0 -e|-p filename,-e filename : Edit file,-p filename : Display file
opt=$1
filename=$2
checkfile()
{ if [ -z "$filename" ]
then
echo "File name missing"
exit 1
elif [ ! -f $filename ]
then
echo "the file does not exist!"
exit 2
fi
}
case $opt in
-e|-E)
checkfile
echo "Edit file"
;;
-p|-P)
checkfile
echo "Displaying file"
;;
*)
echo "Bad argument!"
echo "Usage:`basename $0`-e|-p filename, -e filename:Edit file, -p filename:Display file"
esac
练习使用getopts处理命令行选项
编写shell脚本,该脚本接收多个命令行参数和选项,具体包括如下:
1)使用getopts解析命令行选项,选项包括-f以及-o,并且-f必须带上一个参数,该参数为文件绝对路径。-o选项也必须带上一个参数,该参数为目录绝对路径
2)-f选项作用为:判断-f后跟的参数对应的文件是否存在,如果不存在则输出“The source file do not exist!”并退出
3)-o选项作用为:判断-o后跟的参数对应的目录是否存在,如果不存在则输出“The output path do not exists!”并退出
4)如果没有为需要的选项指定参数,则显示提示信息“The option requires an argument”并退出
5)如果指定的选项为无效选项,则显示提示信息“Invalid option”并退出
while getopts :f:o opt
do
case "$opt" in
f)
if [ ! -f "$OPTARG" ]
then
echo "The source file do not exist"
exit
fi
;;
o)
if [ ! -d "$OPTARG" ]
then
echo "The output path do not exist!"
exit
fi
;;
:)
echo "The option requires an arguments"
exit
;;
*)
echo "Invalid option"
exit
esac
done
实验七:Shell重定向与管道
练习标准输入、标准输出以及标准错误的重定向操作
-
ls显示当前目录,并将结果重定向到文件/home/output.txt中
ls >> /home/output.txt
-
echo出当前时间,并重定向到文件/home/output.txt中
echo $(data) >> /home/output.txt
-
统计/home/output.txt文件中有多少行文本
wc -l /home/output.txt
编写一脚本:
(1) 该脚本接收多个输入参数(表示目录)
(2) 该脚本对所有参数进行遍历,遍历过程中,找到指定目录中以*.tmp为后缀的文件,并将其删除
(3) 遍历产生的错误信息追加写入到文件/home/errors.log文件中
#!/bin/bash
for dir in "$@";
do
if [ ! -d "$dir" ]
then
echo "error, $dir Inexestence" >> /home/errors.log
continue
fi
find "$dir" -name "*.tmp" -type f -delete 2 >> /home/errors.log
done
echo "finish"
编写一脚本
(1) 该脚本遍历文件/etc/passwd文件内容的每一行
(2) 输出每一行的内容
(3) 计数统计文件的行数
(4) 遍历结束后,输出文件的总行数
#!/bin/bash
count=0
while IFS= read -r line;
do
echo "$line"
((count++))
done < /etc/passwd
echo "文件总行数:$count"
*练习使用常见的管道完成特定的任务
-
编写一个管道,将 ls 命令的输出发送到 grep 命令,查看文件 log.txt 是否存在于当前目录下
ls | grep log.txt
-
编写一个管道,将who 命令的输出将作为 sort 命令的输入,显示按用户名排序后的当前登录系统的用户的信息,并将输出重定向到文件lis.txt
who | sort > lis.txt
-
编写一个管道,该管道使用 tr 命令将 os.txt 文件中的内容转化为大写,并使用 sort 命令将内容排序
tr a-z A-Z < os.txt | sort
-
编写一个管道,将os.txt文件中的内容排序和去重后,输出到newos.txt
sort os.txt | uniq > newos.txt
-
编写一个管道,删除打印输出文本中的数字
echo hili2j3k78mn | tr -d [:digit:]
-
编写一个管道,该管道列出当前账号最常使用的10个命令
history | awk '{print $2}' | sort | uniq -c | sort -nr | head -n 10
实验八:sed与awk
*练习sed的基本命令,包括插入、追加、更改、删除等命令
给定一文件sedtest.txt,文件内容如下:
Hello
Word
Abc
Jkl
-
使用sed向文本sedtest.txt的第三行插入一行数据insertdata
sed '3i insertdata' sedtest.txt
-
使用sed向sedtest.txt文本的第三行追加一行数据appenddata
sed '3a appenddata' sedtest.txt
-
使用sed将sedtest.txt文本的第三行更改为changedata
cat sedtest.txt | sed '3c changedata' sedtest.txt
-
使用sed命令,对sedtest.txt文本进行操作,从Hello所在行到Abc所在行的每行数据前插入insertdata
cat sedtest.txt | sed '1,3i insertdata'
-
使用sed命令,对sedtest.txt文本进行操作,从Hello所在行到Abc所在行的每行数据追加appenddata
cat sedtest.txt | sed '1,3a appenddata'
-
使用sed命令,对sedtest.txt文本进行操作,将Hello所在行到Abc所在行更改为changedata
cat sedtest.txt | sed '1,3c changedata'
-
使用sed命令,删除sedtest.txt文本第一行数据
sed '1d' sedtest.txt
-
使用sed命令,删除sedtest.txt文本第一行到第三行数据
sed '1,3d' sedtest.txt
-
使用sed命令,对sedtest.txt文本进行操作,将第3行中的’b’替换为’B’
sed '3s/b/B/g' sedtest.txt
练习awk的基本命令
student.txt文本内容如下:
ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Gao 99 83 93 91.66
(1)定义两个动作:读入数据前打印“这是一张成绩单”;打印文件的第二个字段和第六个字段。
awk 'BEGIN{printf "This is a transcript\n"}{printf $2 "\t" $6 "\n"}' student.txt
(2)定义两个动作:打印文件的第二个字段和第六个字段;输出结尾输入“The end”
awk 'END{printf "The End\n"}{printf $2 "\t" $6 "\n"}' student.txt
(3)打印Liming的成绩
awk '/Liming/{print}' student.txt
passwd.txt内容如下:
root:X:0:0:root:/root:/bin/bash
bin:X:1:1:bin:/bin:/sbin/nologin
daemo:X:2:2:daemon:/sbin:/sbin/nologin
(1) 输出passwd.txt文件中以分号分隔的第1和第7字段,显示的不同字段之间以逗号隔开。
awk -F ":" '{print $1 "," $7}' passwd.txt
(2) 输出每次处理的行号,以及当前行以”:”分隔的字段个数。
awk -F ":" '{print NR,NF}' passwd.txt
*实践:签到程序代码
#!/bin/bash
# 首页
function show(){
echo "***welcome***"
echo "**1.check in**"
echo "**2.The record**"
echo "**3.Exit**"
echo "input your choose:"
}
# 签到
function check_in(){
echo "please input your name:"
read name
echo "please input your passwd:"
read password
if test -e /c/Users/YL/userinfo.txt
then
cat userinfo.txt | while read tem_name tem_password
do
if test "$name" = "$tem_name" && "$password" = "$tem_password"
then
hour=`date "+%k"`
#echo $hour
if [ "$hour" != "8" ]
then
echo "check in successfully but you are late"
echo "$name ---late for class --- Time:`date` " >> /c/Users/YL/check.txt
else
echo "check in successfully"
fi
else
continue
fi
done
else
echo "NO such file"
fi
}
# 查询记录
function record(){
if test $# -ne 0
then
echo "$1 here are your records:"
grep "$name" /c/Users/YL/check.txt
else
echo "sorry,please check in first"
fi
}
# 退出
function tuichu(){
echo "Thanks for use"
exit 1
}
# 主方法
function main(){
while test "1" = "1"
do
show
read choose
case $choose in
1)check_in
;;
2)record $name
;;
3)tuichu
;;
*)echo "Incorrect input"
;;
esac
done
}
main