shell脚本编写简单入门

helloworld入门

使用编辑器vim 创建并添加语句
vim helloworld.sh

#! /bin/bash
echo 'helloworld'

#! /bin/bash 是指此脚本使用/bin/bash来解释执行。
echo 输出语句

chmod ug+x helloworld.sh		# 修改文件执行权限
./helloworld.sh			# 执行脚本

chmod命令

u表示user 文件或目录的所有者
g表示group 与文件属主有相同组ID的所有用户
o表示others
a表示所有用户,a为系统默认值
w写的权限
x执行权限
r读权限

数字设定法
计算方法:r=4,w=2,x=1

  • 7 = 4+2+1=读+写+执行
  • 5 = 4+1=读+执行
  • 1 = 执行
    等同于:
chmod u=rwx,g=rx,o=x helloworld.sh

编写规范与建议

1.脚本存放目录需要统一
2.shell脚本的结尾以 .sh
3.脚本开头要有解释器如#!/bin/bash 或者#!/usr/bin/env bash
4.脚本开头注意加时间、作者、联系邮箱、脚本作用等信息

# huhao egon 2022-11-06 version 1 des: xx

5.关键代码应该用#号加上注释
6.成对的符号尽量一次性写出来,防止遗漏

  • 例如大括号{},中括号[ ],小括号(),单引号'',双引号"",反引号``等

7.括号的保留空格习惯

  • 中括号[ ]两端需要留有空格,不然会报错。书写时即可留出空格然后书写内容。
  • 如果不知道大括号{ },中括号[ ],小括号( ),到底哪种括号需要两端留空格,可以在书写这些括号的时候两端都保留空格来进行书写,这样可以有效避免因空格导致的各种错误。

8.流程控制语句一次性书写完再添加内容

#if语句格式一次书写完成
if 条件内容
then
	条件成立后执行的代码
fi

变量

1.定义
变量名=变量值

2.变量定义规则
区分大小写,一般大写
不能有特殊符号
变量值有空格要用单双引号
变量名字不可以用数字开头
等号两边不能有任何空格,如 A = 3 错的

3.变量的使用
基本方式

A=1546
echo $A
输出:
1546

4.删除变量
删除变量unset age

变量值的来源

1.直接赋值

#! /bin/bash
ip="10.10.10.10"
age=18
now_date1=`date "+%F"`
now_date2=$(date "+%F")

2.从脚本的参数获取,即从命令获取

  • $0 是本身
  • $1 是第一个参数
  • $2 是第二个参数
  • ${10} 10以上就要用{}括起来

创建.sh脚本 test.sh

#! /bin/bash
if [ $1 = "start" ];then
        echo "starting"
elif [ $1 = "stop" ];then
        echo "stopping"
elif [ $1 = "restart" ];then
        echo "restartting"
else
        echo "Usage: ./test.sh start:stop:restart"
fi

运行

 chmod +x test.sh			# 设置权限
 ./test.sh stop 				# stop 是传入的变量

3.与用户交互来获取变量值
read -p "请输入您的账号:" name

#! /bin/bash
db_name="huhao"
db_pwd="123456"

read -p "请输入您的账号:" name
read -p "请输入您的密码:" pwd

if [ $name = $db_name ] && [ $pwd = $db_pwd ]:then
        echo "登录成功"
else
        echo "登录失败"
fi

运行

chmod +x test.sh
 ./test.sh
请输入您的账号:huhao
请输入您的密码:123456
登录成功

4.命令结果赋值给变量

``(反撇号)或$()

A=`hostname`
echo $A
输出:
huhaodeMacBook-Pro.local

交互式定义变量

read [选项] 变量名

选项 功能
-p 定义提示用户的信息
-n 定义字符数(限制输入长度)
-s 不显示(用户输入的内容)
-t 定义超时时间
#! /bin/bash
read -p "请输入你的名字:" name
echo $name
read -s -p "请输入密码:" pwd
echo $pwd

定义有类型的变量

declare [选项] 变量名=变量值

选项 功能
-i 将变量看成整数
-r 定义只读变量
-a 定义普通数组,查看普通数组
-A 定义关联数组;查看关联数组
-x 将变量通过环境导出

普通数组

#! /bin/bash
# 直接赋值
arr1=("抽烟" "酒" "烫头")
echo ${arr1[0]}		# 结果:抽烟
echo ${arr1[1]}		# 结果:酒
echo ${arr1[2]}		# 结果:烫头

# 先创建后赋值
declare -a arr2
arr2[0]=12
arr2[1]=34
arr2[2]=56
echo ${arr2[0]}		# 结果:12
echo ${arr2[1]}		# 结果:34
echo ${arr2[2]}		# 结果:56

# 指定下标对应为什么值
arr3=([2]=3.3 [1]=1.1 [3]=4.4)
echo ${arr3[3]}		# 结果:4.4
echo ${arr3[2]}		# 结果:3.3
echo ${arr3[1]}		# 结果:1.1
echo ${array2[0]}		# 结果:		,因为没有定义

关联数组

#! /bin/bash
declare -A info=(["name"]="huhao" ["age"]=28 ["sex"]="male")
echo ${info["name"]}		# 结果:huhao
echo ${info["age"]}			# 结果:28
echo ${info["sex"]}		# 结果:male

系统变量

内置变量 含义
$? 上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误
$0 当前执行的程序或脚本名
$# 脚本后面接的参数的个数
$* 脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
$@ 脚本后面所有参数,参数是独立的,也是全部输出
$1-$9 脚本后面的位置参数,$1表示第1个位置参数,依次类推
${10}-${n} 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上扩起来)
$$ 当前所在进程的进程号,如echo $$
$! 后台运行的最后一个进程号(当前终端)
!$ 调用最后一条命令历史中的参数

判断文件类型

判断参数 含义
-e 判断文件是否存在(任何类型文件)
-f 判断文件是否存在并是一个普通文件
-d 判断文件是否存在并且是一个目录
-L 判断文件是否存在并且是一个软连接文件
-b 判断文件是否存在并且是一个块设备文件
-S 判断文件是否存在并且是一个套接字文件
-c 判断文件是否存在并且是一个字符设备文件
-p 判断文件是否存在并且是一个命名管道软件
-s 判断文件是否存在并且是一个非空文件(有内容)
#! /bin/bash
while true
do 
read -p "输入文件名称或者目录(输入break退出循环):" filename;
if [ $filename = "break" ]
then
        echo "已退出循环";
        break;
fi
if [ -e $filename ]  
then
        echo "经检测,输入的文件或者目录存在...";
else
        echo "经检测,输入的文件或者目录不存在,请重新输入"
fi
if [ -f $filename ]
then 
        echo "进一步检测到,输入的是一个文件且为一个普通文件"
#判断该文件是否为空
if [ -s $filename ]
then 
        echo "该文件非空"
else    
        echo "该文件为空"
fi
#判读文件是否是软链接
if [ -L $filename ]
then 
        echo "该文件是一个软链接";
fi
# 判读文件是否可读
if [ -r $filename ]
then
        echo "该文件可读";
else  
        echo "该文件不可读";
fi
#判断文件是否可写
if [ -w $filename ]
then
        echo "该文件可写入";
else
        echo "该文件不可写入";
fi
#该文件是否可执行
if [ -x $filename ]
then 
        echo "该文件可执行";
else
        echo "该文件不可执行";
fi

else
if [ -c $filename ]
then
        echo "该文件为字符设备文件";
fi
if [ -b $filename ]
then
        echo "该文件为块设备文件"
fi
if [ -p $filename ]
then 
        echo "该文件为管道文件";
fi
fi
if [ -d $filename ]
then    
        echo "进一步检查到,输入的是一个目录";
fi 
done

判断整数 常用

参数 含义
-eq 相等
-ne 不等
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于

算数运算符

符号 中文词义
+
-
*
/
% 取余
# 浮点运算
bc #bc计算器

# 整数运算
expr
$(())
$[]
let
#! /bin/bash
x=1
y=2

expr $x+$y				# 结果:3
expr $x \* $y			# 结果:2,乘法需要加 \ ,因为 * 有特殊意义

echo $((1+2))			# 结果:3
echo $(( $x + $y ))		# 结果:3

echo $[ $x + $y ]		# 结果:3

let z=x+y
echo $z					# 结果:3

echo "5.6*3.2+6.7^2"|bc #62.7

判断字符串 常用

判断参数 含义
-z 判断是否为空字符串,字符串长度为0成立
-n 判断是否为非空字符串,字符串长度不为0成立
string1 = string2 判断字符串是否相等
string1 != string2 判断字符串是否不相等
#!/bin/bash
x1=""
y2="123abc"
[ -n "$x1" ]
echo $?			# 1,x的长度为0

[ -n "$y1" ]
echo $?			# 0,y的长度不为0

x2=""
y2="123abc"
[ -z "$x2" ]
echo $?			# 0,x的长度为0

[ -z "$y2" ]
echo $?			# 1,y的长度不为0

x3=""
y3="123abc"
[ "$x3" = "$y3" ]
echo $?			# 1,x不等于y

x4=""
y4="123abc"
[ "$x4" != "$y4" ]
echo $?			# 0,x不等于y

补充[[ ]]

[[ ]][ ]基本一样,不同的是[[ ]]支持正则表达式

#!/bin/bash
[ $# -ne 1 ] && echo "只能传入一个参数" && exit

# 只能是数字
[[ ! $1 =~ ^[0-9]+$ ]] && echo "只能传入数字" && exit

echo "ko ----> $1"

常量

常量:不变的量

readonly m=111		# 使用常量关键字
AGE=18				# 或者使用大写变量名来提示自己这是常量

获取变量值的长度

#! /bin/bash
x="hello"
y=123456
z=3.12

echo ${#x}		# 结果:5
echo ${#y}		# 结果:6
echo ${#z}		# 结果:4

切片

#! /bin/bash
msg="hello123"
echo ${msg:1}		# 结果:ello123	,从第一个开始切
echo ${msg:1:3}		# 结果:ell	,从第一个开始切,切三个

截断

#! /bin/bash
url="www.huhaowb.com"
# 从左开始截断
echo ${url#www.}				# 结果:huhaowb.com
echo ${url#*.}					# 结果:huhaowb.com		,截断到第一个点
echo ${url##*.}					# com		,截断到最后第一个点

# 从右开始截断
echo ${url%.com}					# 结果:www.huhaowb
echo ${url%.*}					# 结果:www.huhaowb		,从最后截断第一个点
echo ${url%%.*}					# 结果:www		,从最后截断到最后一个点

替换

#! /bin/bash
url="www.huhaowb.com"
echo ${url/huhaowb/baidu}			# 结果:www.baidu.com
echo ${url/c/C}					# 结果:www.huhaowb.Com

# 替换所有
echo ${url//h/H}				# 结果:www.HuHaowb.com

if语句

# 单分支
if [ 条件1 ];then
	代码1
	代码2
	...
fi
# 双分支
if [ 条件1 ];then
	代码1
	代码2
	...
else
	代码1
	代码2
	...
fi
# 多分支
if [ 条件1 ];then
	代码1
	代码2
	...
elif [ 条件2 ];then
	代码1
	代码2
	...
elif [ 条件3 ];then
	代码1
	代码2
	...
else
	代码1
	代码2
	...
fi

case语句

case $x in
1)
	代码1
	代码2
	代码3
	;;
2)
	代码1
	代码2
	代码3
	;;
3|4|5)			# 变量为3、4、5都可以进入这个代码块
	代码1
	代码2
	代码3
	;;
...
*)
	代码1
	代码2
	代码3
esac

案例:输入名字,输出系统权限身份

#!/bin/bash
read -p "please input your name: " name
if [ -z "$name" ];then
	echo "必须输入用户名" 
fi
	
case $name in
"root")
	echo "管理员"
	;;
"huhao")
	echo "普通用户"
	;;
*)
	echo "访客"
esac

while循环

条件为真则运行循环体代码,直到条件变为假则结束循环

while 条件	
do
	代码1
	代码1
	代码1
done

案例:打印0~7

#! /bin/bash
count=0
while [ $count -le 7 ]	#小于等于7
do
	echo $count
	let count++
done	

until循环

条件为假则运行循环体代码,直到条件变为真则结束循环

until 条件	
do
	代码1
	代码1
	代码1
done

案例:打印0~7

#! /bin/bash
count=0
until [ $count -gt 7 ]	#大于7
do
	echo $count
	let count++
done	

break终止本层循环

#! /bin/bash
count=0
while :	
do
	if [ $count -le 7 ];then
		break
	fi
	echo $count
	let count++
done

continue终止本次循环

#! /bin/bash
count=0
while [ $count -le 7 ]	
do
	if [ $count -eq 4 ];then
		continue
	fi
	echo $count
	let count++
done

for循环

for x in 参数值1 参数值2 参数值3
do
	代码1
	代码1
	代码1
done

案例:遍历桌面文件

#! /bin/bash
for x in `ls Desktop`
do
	echo "hello $x"
done

select选择循环

#! /bin/bash
select choice in {"退出","取款","转账","查询余额"}
do
        echo "选项是:$choice"
        case $choice in
        "退出")
                break
                ;;
        "取款")
                echo "正在取款"
                ;;
        "转账")
                echo "正在转账"
                ;;
        "查询余额")
                echo "正在查询余额"
                ;;
        *)
                echo "其他功能还没有开发"
        esac
done

函数

function f1(){
	echo "第一种方式"
}
function f2{
	echo "第二种方式"
}
f1(){
	echo "第三种方式"
}

函数参数

function f1(){
	echo "$1"
	echo "$2"
	echo "$3"
	echo "$4"
	echo "$5"
}
f1 111 222 333 444 555 

函数返回值

1.使用return返回值
使用return返回值,只能返回1-255的整数
函数使用return返回值,通常只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败
2.使用echo返回值
使用echo可以返回任何字符串结果
通常用于返回数据,比如一个字符串值或者列表值

获取return返回值

使用$?接收上一程序的返回值状态,也就是return的值

#! /bin/bash
getResult(){
    if [ -d "Desktop" ];then
        return 1
    else
        return 0
    fi
}
main(){
    getResult
    res=$?
    echo ${res}       
    if [[ $res -eq 1 ]]; then
            echo 1
    else  
            echo 0
    fi
}
main

通过echo返回一个任意值

在函数最后使用echo打印一个值,在调用该函数的地方,可以通过$(function_name)把结果传给一个新的变量,也就获取了函数的处理结果

#! /bin/bash
function foo(){ 
 echo $1;
}
result=$(foo 33)
echo result is ${result}

  目录