shell脚本

756 阅读4分钟

前言

shell 也是我们知识的一个扩展,平常开发中我们可能用不到这个,但是要是想作为一个高效率的懒人程序员,那么这个还是要掌握的,某种情况下他能减轻我们繁琐的操作,能让我们将需要等待的流程操作归一化,这样我们也能省下来喝杯茶唠嗑的时间,或者看看一篇文章,岂不美哉

shell文档

传递参数

shell 脚本运行时是可以接手参数的,跟我们的函数一样,执行脚本时只需要在后面,加个空格直接传递参数即可

例如,参数1:./shell.sh 1

//echo 为输出log
echo "--脚本接收参数测试--"
echo "我是传递的第一个参数,执行脚本文件名 \$0: $0"
echo "我是传递的第二个参数,实际第一个传递参数 \$1: $1"
echo "我是传递的第三个参数,实际第二个传递参数 \$2: $2"
echo "显示所有传递的参数 \$* \$@:$* $@"
echo "实际传递的参数个数(不包含文件名) \$#:$#"

*、@、#

*、@默认都是获取集合、字符串所有变量的关键字,但其作为参数时,则又有不同

*、@ 的不同,只有在双引号中体现出来。假设在脚本运行时写了三个参数 123,
则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。

# 则是对上面集合、字符的全部计数,计算出他们的个数、长度

字符串变量

echo '--打印变量字符串--'
str='哈哈哈'
str2="拼接了变量:$str"
str3="拼接了变量:${str}还追截了尾巴"
str4="拼接了变量,读取其字符长度#:${#str}"
str5='单引号,单纯字符串,拼接变量转换功能无效:${#str}'
str6=${str:1:2}
echo $str
echo $str2
echo $str3
echo $str4
echo $str5
echo "截取字符串:${str6} -- 指令:\${str:start:length}"

数组

echo '--打印数组--'
array=(1, 2, 3, 4)
echo "使用下标获取第n个元素:${array[1]}"
echo "获取所有元素之 *、@ -- *${array[*]} -- @${array[@]}"
echo "获取总长度和字符串一样 ${#array[*]}"

运算

运算符,如果感觉运算符不够用,那么可以参考这里,后面的流程判断也会用到

echo '--运算--'
res=`expr 1 + 2`  //expr就是计算的,需要用到反引号
echo "两数之和:$res"
a=10
b=20
res2=`expr $a \* $b`
echo "两数之积,注意关键字转义\\\*:$res2"

条件流程语句

if、else、else if

条件语句比较简单,就是多了个 then 开始、fi 结尾

echo '--if条件语句--'
a=1
b=2
if [[ $a < $b ]]
then
	echo 'a < b'
fi

if [[ $a < $b ]]
then
	echo 'a < b'
else if [[ $a > b ]]
then
	echo 'a > b'
else 
	echo 'a = b'
fi

注意事项:默认判断会看到使用单括号的,单括号需要转义或使用规定的比较符号,双括号不需要

echo "==、!=、>、<、>=、<=这些运算符如果发现无法使用,那么可能需要转义"
echo "-eq(==)、-ne(!=)、-gt(>)、-lt(<)、-ge(>=)、-le(<=) 比较单次的缩写,用他们的目的就是避免常见运算符需要转义问题"
# if [ $a \< $b ]  //这个默认需要转义
# if [ $a -lt $b ] //或者是直接使用给定的字符比较
if [[ $a < $b ]]  //双括号也能避免转义的问题
then
	echo 'a < b'
else if [[ $a > b ]]
then
	echo 'a > b'
else 
	echo 'a = b'
fi

字符串的等号判断有有点不一样,单等号也是对比是否相当,请勿认为是赋值

字符串的判断最好用 = 号, == 也可以
sstr="fffff"
sstr2="fffff"
# if [[ $sstr == $sstr2 ]]
if [[ $sstr = $sstr2 ]]
then
	echo "str1 == str2"
else 
	echo "str1 != str2"
fi

循环、遍历

比较常见的就是 for、while 了,这里面需要使用 do ... done 代替常见的大括号

echo '--循环遍历(读取列表并遍历打印)--'
for path in `ls ./`
do
	echo $path
done


echo '\n--循环while、for(不满足条件跳出)
num=1
num2=1
while (( $num < 10 || $num2 < 12 )) 
do
	echo $num
        # let "num++"
	num=`expr $num + 1`
	num2=`expr $num2 + 1`
done

for 不多介绍了
'for ( ; ; )'

read 读取外部输入内容

echo '--读取外部输入read--'
echo '请输入你的年龄'
read age
if [[ $age > 35 ]]
then
	echo "这个社会不需要大于35岁的老人"
else
	echo "社会需要你,年轻小伙子/小姑娘"
fi

可以使用读取 + 循环做一个硬性判断,用户也可以强制结束循环

添加一个读取功能
echo "\n--请输入大于10的数字--Ctrl-D退出循环,继续往后执行 -- Ctrl-C结束脚本运行"
read info
while (( $info < 10 )) 
do
	echo "你输入的是:${info},请重新输入"
	read info
done

格式化打印 printf

echo '--格式化打印printf(C语言一样,相信有时候会用的到)--'
printf "姓名:%s 性别:%s 身高%.2f\n" 小月亮 女 171.1111

执行命令反引号``

反引号``就是执行命令的语句,这里面我们打印一个日期 date 做测试,前面也有用到 expr 计算

echo '--获取命令执行结果(打印日期date)--'
echo '执行命令并获取结果 `命令`'
echo `date`

还可以用来读取执行返回的信息

echo '--读取执行返回信息--'
str=`cat ./file1.txt`
echo $str

判断文件

判断文件是否存在,可以使用 tes,也可以直接中括号 + -e
# if test -e ./file.txt
if [ -e ./file1.txt ]
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi
echo '-s(文件是否为空) -e(文件是否存在) 比较常用'

函数

echo "--函数(实际上跟执行新脚本类似)"
add() {
	echo '调用了函数'
	echo "第一个参数为 $1 !"
}
add 1

文件包含与中定向

# 文件包含(一般用不到,除非写比较大的功能,或者复用功能)
. filename 或者 source filename 即可直接使用外部参数等 -- 注意空格'

出入重定向

echo "--输出重定向到文件 > >>"

echo 'command > file	将输出重定向到 file'
echo 'command >> file	将输出追加的方式重定向到 file'

echo "将输出重定向到 file" > 1.txt
echo "将输出追加的方式重定向到 file" >> 1.txt

给脚本文件执行权限 chmod

cd 到指定目录,使用 ./filename.sh 执行,可以理解为使用相对路径,直接执行该目录下对应路径的脚本,否则可能去到指定目录查找执行脚本,我们的脚本基本不可能写到哪里

也可以直接给一个绝对路径,以保证执行没问题,如果涉及到导出 相对路径容易出问题,直接全绝对路径即可(例如:设置定时操作)

#使脚本具有执行权限
chmod +x ./filename.sh

实践案例

我们有一个简单的脚本任务,将当前目录下的 subschemas 子目录,中的二级目录的文件全部读取,并追加到 subschemas 中的 base.prisma 后面,并且最后形成的文件导出到脚本所在目录,名字为scheme.prisma

实现如下所示

readAndWrite() {
	while read line
	do
		echo $line >> $2
	done < $1
}

echo "开始执行"
rm -rf ./scheme.prisma
cd subschemas
readAndWrite ./base.prisma ../scheme.prisma

for path in `ls ./`
do
	if test -d ${path}
	then
		cd ${path}
		for subpath in `ls ./`
			do
				if test -e ${subpath}
				then
					readAndWrite ./${subpath} ../../scheme.prisma
				fi
			done
		cd ..
	fi
done

最后

除了上面的相信可以看到,脚本语言其实很简单,可以做的却很多,其还有一个更加重要的功能,那就是直接执行 linux 终端指令

我们可以直接将终端直接写进脚本,这样就可以顺序实行了,是不是很方便呢

yarn
yarn build

另外,脚本会用到的很多执行都是 linux 指令,具体可以学习一些 linux 相关,相对于包含更加复杂的内容逻辑操作,shell 脚本明表现不是很优秀,可以使用 python、javascript 脚本编写