前段时间,在网络上学习了一个Shell脚本的课程。通过这个课程的学习,让我对Shell脚本有了全新的认识,没有想到Shell脚本功能这么强大,这么方便。意识到这个课程的重要性,就把课程中的重点知识,以笔记形式记录下来了。
先介绍下Shell Script。所谓Shell Script,就是使用命令行工具,在Mac电脑上,常用的就是终端(Terminal)了,在终端上执行的命令就是Script了。
介绍脚本之前,先介绍下bash和zsh的区别
1.bash与zsh的区别
bash(Bourne Again Shell)是许多Linux和Unix系统默认的命令行解释器,Mac电脑也有,不过不是默认的解释器。
ZSH(Z Shell)是Bash的一个替代品,
现在Mac电脑上默认的命令行解释器了(打开终端就显示了),在bash基础上扩展了一些功能。如:自动补全,插件和主题,别名等功能,不过在这次没有用到这些功能。
2.创建一个shell文件并执行
这里创建shell文件的方式很多。这里是在终端上使用vim创建的,
直接在终端上输入vim test.sh ,(当然要cd到对应目录哟)
然后在test.sh输入了echo “hello world”,
然后按esc后,按:wq保存并退出, 执行test.sh,提示没有权限执行(“Permission denied”),这就是提示升级权限。
然后使用 chmod 777 ./test.sh 升级到最高权限。这样就可以执行test.sh文件了。
3.判断文件/目录
直接上脚本了
path=$PWD
testDir=$path”/test”
testfile=”a.txt”
判断目录是否存在,若存在就删除, 否则就创建
if [ -d $testDir ]; then
echo “存在该目录”
rm -rf $testDir
else
echo “不存在该目录”
mkdir $testDir
fi
当然,还有使用 !判断文件不存在的方式
if [ ! -d $testDir ]
then
echo “不存在该目录 “$testDir
mkdir $testDir
fi
这里需要注意的是 if语句的空格位置。
对文件的判断与目录差不多,唯一的区别就是 -d 替换成 -f
判断文件是否存在, 不存在就创建,
if [ ! -f $testDir”/”$testfile ]
then
echo “不存在该文件 “
#使用touch 创建一个空文件
touch $testDir”/”$testfile
fi
4.数组
shell脚本的数组分静态数组和动态数组
静态数组
array=(“nihao” “hello world” “test”)
动态数组
array1=($(ls))
echo $array
output — nihao #这里只能打印数组的第一个元素
echo $array1
output — a.txt
打印数组内所有元素
echo “value: “${array[*]}
output — value: nihao hello world test
打印数组的个数
echo “count: “${#array[*]}
output — count: 3
5.for 循环
for 循环数组
循环遍历array数组内元素
for value in ${array[*]}
do
echo “the value: “$value
done
循环遍历1到10的数字序列,每次增加2
for value in ${1..10..2}
do
echo “the value: “$value
done
使用for循环遍历目标文件夹中的所有文件
for filepath in $testDir/*
do
# 输出带目录的文件名
echo “filepath: $filepath”
#output — filepath: /Users/{USER}/Desktop/build/test/b.txt
#output — filepath: /Users/{USER}/Desktop/build/test/c.txt
#若当前文件夹没有文件,则输出*
#output -- filepath: /Users/{USER}/Desktop/build/test/*
# ----在此处可以添加对文件的其他操作,如复制文件、删除文件等
done
使用函数方式带参数地遍历文件夹。
readDir() {
#for file in ‘ls $1’ #这个是错误的。看出区别了吗!
for file in ls $1
#注意此处这是两个反引号,表示运行系统命令
do
filepath1=$1
#echo “list: “$filepath1” file:”$file
if [ -f $filepath1″/”$file ]; then
#是文件
echo $filepath1″/”$file
else
#是目录 -- 递归遍历子目录
readDir $filepath1"/"$file
fi
done
}
readDir $testDir
output
/Users/{USER}/Desktop/build/test/b.txt
/Users/{USER}/Desktop/build/test/c.txt
/Users/{USER}/Desktop/build/test/tes3/b3.txt
/Users/{USER}/Desktop/build/test/tes4/b4.txt
/Users/{USER}/Desktop/build/test/tes4/c4.txt
6.read读取方式
选项说明:
-a:将分裂后的字段依次存储到指定的数组中,存储的起始位置从数组的index=0开始。
-d:指定读取行的结束符号。默认结束符号为换行符。
-n:限制读取N个字符就自动结束读取,如果没有读满N个字符就按下回车或遇到换行符,则也会结束读取。
-N:严格要求读满N个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束。其中换行符或回车算一个字符。
-p:给出提示符。默认不支持”\n”换行,要换行需要特殊处理,见下文示例。例如,”-p 请输入密码:”
-r:禁止反斜线的转义功能。这意味着”\”会变成文本的一部分。
-s:静默模式。输入的内容不会回显在屏幕上。
-t:给出超时时间,在达到超时时间时,read退出并返回错误。也就是说不会读取任何内容,即使已经输入了一部分。-u:从给定文件描述符(fd=N)中读取数据。
使用举例说明
使用-p选项给出输入提示
read -p “please enter you name: “
“-p”选项默认不带换行功能,且也不支持”\n”换行。但通过$’string’的方式特殊处理,就可以实现换行的功能
read -p $’Enter your name: \n’
read的输入方式
echo “please input your password”
read -s password
echo “password “$password
以上讲完了基本脚本的使用,下面再介绍几个非常有用的命令: cat,grep,sed
7.cat
cat 命令用于连接文件并打印到标准输出设备上。
参数说明
-n 或 –number 由 1 开始对所有输出的行数编号
-b 或 –number-nonblank 和 -n 相似,只不过对于空白行不编号
-s 或 –squeeze-blank 当遇到有连续两行以上的空白行,就代换为一行的空白行
-v 或 –show-nonprinting 使用 ^ 和 M- 符号,除了 LFD 和 TAB 之外
-E 或 –show-ends 在每行结束处显示 $
-T 或 –show-tabs 将 TAB 字符显示为 ^I
-e 等价于 -vE
-A –show-all 等价于 -vET
-t 等价于-vT选项
举例说明
7.1 合并文件
把 textfile1 的文档内容加上行号后输入 textfile2 这个文档里:
cat -n textfile1 > textfile2
合并多个文件
cat -b textfile1 textfile2 >> textfile3
7.2 清空 /etc/test.txt 文档内容:
cat /dev/null > /etc/test.txt
cat 也可以用来制作镜像文件。例如要制作软盘的镜像文件,将软盘放好后输入:
cat /dev/fd0 > OUTFILE
相反的,如果想把 image file 写到软盘,输入:
cat IMG_FILE > /dev/fd0
注:
- OUTFILE 指输出的镜像文件名。
- IMG_FILE 指镜像文件。
- 若从镜像文件写回 device 时,device 容量需与相当。
- 通常用制作开机磁片
7.3 创建文件并写入数据
path=$PWD
testDir=$path”/test”
testfile=”a.txt”
cat >> $testDir”/”$testfile “hello world”
还有,写入多行内容
cat > ./a.txt <<EOF
你好, hello world
你好2, hello world2
你好3, hello world3
EOF
注意:以上命令在终端执行没有问题,同样的命令在if里面就失败了,暂不原因
判断文件是否存在, 不存在就创建,
if [ ! -f $testDir”/”$testfile ]
then
echo “不存在该文件 “
使用cat 创建一个文件并写入数据
touch $testDir”/”$testfile
cat > $testDir”/”$testfile <<EOF
你好, hello world
EOF
fi
失败,提示“ syntax error: unexpected end of file”
8 grep命令
grep命令是一种强大的文本搜索工具,根据用户指定的“模式”对目标文本进行匹配检查,打印匹配到的行
参数 说明
-c 只输出匹配行的数量
-i 搜索时忽略大小写
-h 查询多文件时不显示文件名
-l 只列出符合匹配的文件名,而不列出具体的匹配行
-n 列出所有的匹配行并显示行号
-s 不显示不存在或无匹配文本的错误信息
-v 显示不包含匹配文本的所有行
-w 匹配整词
-x -x匹配整行
-r 递归搜索,不仅搜索当前工作目录,并且搜索子目录
-q 禁止输出任何结果,以退出状态表示搜索是否成功
-b 打印匹配行距文件头部的偏移量,以字节为单位
-o 与-b选项结合使用,打印匹配词距文件头部的偏移量,以字节为单位
-E 支持扩展的正则表达式
-F 不支持正则表达式,按照字符串的字面意思进行匹配
在项目中,我们主要用来匹配字符串。例如
在a.txt文件中查找array3所对应的字符串
array3=(“test” “123” “hao”)
for value in ${array3[*]}
do
#匹配并在终端显示出来
#grep -i $value $testDir”/”$testfile
#匹配并以颜色方式在终端显示出来
grep -i --color $value $testDir"/"$testfile
done
注意:
上实例中,a.txt文件中还有”hao”字符串,但是没有搜寻出来,为什么呢?原因是在搜寻第二个字符“123”时,没有搜到就中断了。怎么解决呢?其实就是把.sh开头的set -e注释掉就可以了。
!/bin/bash
set -e
再次运行.sh. 如下图
还有关于grep匹配的问题
for value in ${array3[*]}
do
res=$(grep -i –color $value $testDir”/”$testfile)
echo "res "$res
#$?变量保存了上一条命令的返回状态码,如果匹配成功则返回0。1表示失败
if [ $? -eq 0 ]; then
echo "匹配到结果"
else
echo "未匹配到结果"
fi
#-n选项用于判断字符串是否非空,如果变量$result非空,则匹配到了结果。
if [ -n "$result" ]; then
echo "匹配到结果"
else
echo "未匹配到结果"
fi
#-q选项可让grep在匹配成功时不输出任何信息,只返回匹配结果。
if grep -i -p --color $value $testDir"/"$testfile
then
echo "匹配到结果"
else
echo "未匹配到结果"
fi
#搜寻的结果 重定向到b.txt文件中
grep -i --color $value $testDir"/"$testfile >> $testDir"/b.txt"
done
9 sed命令
grep sed awk 被称为linux文本三剑客
sed编辑器
sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。
sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本文件中。
常用选项:
-e 或–expression=:表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一般在执行多个操作命令使用
-f 或–file=:表示用指定的脚本文件来处理输入的文本文件。
-h 或–help:显示帮助。
-n、–quiet 或 silent:禁止sed编辑器输出,但可以与p命令一起使用完成输出。
-i:直接修改目标文本文件。
常用操作:
s:替换,替换指定字符。
d:删除,删除选定的行。
a:增加,在当前行下面增加一行指定内容。
i:插入,在选定行上面插入一行指定内容。
c:替换,将选定行替换为指定内容。
y:字符转换,转换前后的字符长度必须相同。
p:打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与“-n”选项一起使用。
=:打印行号。
l(小写L):打印数据流中的文本和不可打印的ASCII字符(比如结束符$、制表符\t)
举例:
打印内容:
sed -n -e ‘p’ $testDir”/”$testfile
删除 d
删除行:
sed ‘d’ $testDir”/”$testfile #全删
sed ‘3d’ $testDir”/”$testfile
sed ‘2,4d’ $testDir”/”$testfile
sed ‘$d’ $testDir”/”$testfile
替换 s
行范围 s/旧字符串/新字符串/替换标记
注意:替换标记的四种含义
4种替换标记:
数字:表明新字符串将替换第几处匹配的地方
g:表明新字符串将会替换所有匹配的地方
p:打印与替换命令匹配的行,与-n一起使用
w 文件:将替换的结果写到文件中
sed -n ‘s/root/admin/2p’ /etc/passwd
sed -n ‘s/root/admin/g’ /etc/passwd
sed -n ‘s/root/admin/p’ /etc/passwd
sed ‘1,20 s/^/#/w out.txt’ /etc/passwd
写入out.txt文件
实际举例:
readDir2() {
#for file in ‘ls $1’ #这个是错误的。看出区别了吗!
for file in ls $1
#注意此处这是两个反引号,表示运行系统命令
do
filepath1=$1
#echo “list: “$filepath1” file:”$file
if [ -f $filepath1″/”$file ]; then
#是文件
#直接替换 a.txt文件中的oldStr 为newStr,且是全部替换(g)
sed -i ” ‘s/oldStr/newStr/g’ $filepath1″/”$file
#直接替换 a.txt文件中的oldStr 为newStr,且是替换第一个
sed -i '' 's/oldStr/newStr/' $filepath1"/"$file
else
#是目录 -- 递归遍历子目录
readDir $filepath1"/"$file
fi
done
}
readDir2 $testDir
以上就是这次课堂笔记。
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/422163.html