文件的格式及执行
文件格式
文件第一行标识需要用什么语言执行脚本。文件以 .sh 结尾,如test.sh
#! /bin/bash
文件执行
修改执行权限后执行
#修改文件权限
chmod +x test.sh
使用source执行
不用修改执行权限,直接执行。要保证在当前文件的绝对路径下
source ./test.sh
使用bash执行
bash执行文件,会开启个新的进程
bash ./test.sh
单引号 双引号 反引号
关于变量
#! /bin/bash
url="shenshuai89@qq.com"
#单引号不会转化变量,把内容作为完整字符串输出
website1='shell:${url}'
#双引号可以把内部的变量进行转化
#使用双引号包围变量,可以 使变量内的空白以及换行都能正确显示
website2="shell:${url}"
#单引号输出 shell:${url}
echo $website1
#双引号输出 shell:shenshuai89@qq.com
echo $website2
# 反引号内放的是linux命令,会把命令执行的结果作为字符串打印出来
`linux命令`
[root@VM-0-11-centos code]# params=`ls`
[root@VM-0-11-centos code]# echo $params
dockerDemo nodeapi
定义变量和取消变量
name="123"
echo ${name}
# 输出:123
unset name
echo ${name}
#
shell变量面试题
[root@VM-0-11-centos shell]# echo user1=`whoami` > who.sh
[root@VM-0-11-centos shell]# echo $user1
[root@VM-0-11-centos shell]# source who.sh
[root@VM-0-11-centos shell]# echo $user1
root
[root@VM-0-11-centos shell]# sh
sh-4.2# echo $user1
sh-4.2#
- 每次调用bash都会开启一个子shell,不保留当前shell变量。
- 调用source是在当前shell环境加载脚本,因此会保留变量
关于格式
```bash使用双引号包围变量,可以使变量内的空白以及换行都能正确显示
所有结果整行输出,不进行换行
echo $(ls -l)
结果会做格式化显示,有空格和换行
echo “$(ls -l)”
字符串可以由单引号' '包围,也可以由双引号" "包围,也可以不用引号。它们之间是有区别<br />三种形式的区别:<br />1) 由单引号' '包围的字符串:
- 任何字符都会原样输出,在其中使用变量是无效的。
- 字符串中不能出现单引号,即使对单引号进行转义也不行。
<br />2) 由双引号" "包围的字符串:
- 如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
- 字符串中可以出现双引号,只要它被转义了就行。
<br />3) 不被引号包围的字符串
- 不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。
- 字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
```bash
#!/bin/bash
n=66
str1=shenshuai89@qq.com$n str2="shell \"script\" $n"
str3='中文网 $n'
echo $str1
echo $str2
echo $str3
#输出结果
# shenshuai89@qq.com66
# shell "script" 66
# 中文网 $n
str1 中包含了$n,它被解析为变量 n 的引用。$n后边有空格,紧随空格的是 str2;Shell 将 str2 解释为一个新的变量名,而不是作为字符串 str1 的一部分。
str2 中包含了引号,但是被转义了(由反斜杠\开头的表示转义字符)。str2 中也包含了$n,它也被解析为变量 n 的引用。
str3 中也包含了$n,但是仅仅是作为普通字符,并没有解析为变量 n 的引用。
特殊符号
$$ | 当前 Shell 进程 PID |
---|---|
$0 | 当前脚本的绝对路径+文件名 |
$1 | 第一个参数 |
$2 | 第二个参数 |
$# | 传递给脚本或函数的参数个数。 |
$@ | 传递给脚本或函数的所有参数。 |
$* | 传递给脚本或函数的所有参数。 |
$? | 表示上一个命令的退出状态,或者上一个函数的返回值 |
function get() {
echo "Process ID: $$"
echo "File Name: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "All parameters 1: $@"
echo "All parameters 2: $*"
echo "Total: $#"
}
get js shell
$?上个命令的退出状态
if [ "$1" == 100 ]
then
exit 0
else
exit 1
fi
需要使用bash开启新进程测试,否则会退出
#测试
bash ./return.sh
echo $?
# 输出1
bash ./return.sh 100
echo $?
# 输出1
$?函数的返回值
function add() {
return $(($1+$2))
}
add 11 24
echo $?
字符串
子串操作
mingyan=goodgoodstudy,daydayup!
${变量} 返回变量值
${#变量} 返回变量长度
${变量:start} 返回变量start数值之后的字符,且包含start位置的字符
${变量:start:length} 提取start之后的 [length长度]的字符,
${变量#word} 从变量开头删除最短匹配的word子串 ${mingyan:good}
${变量##word} 从变量开头删除最长匹配的word子串
${变量%word} 从变量结尾删除最短的word
${变量%%word} 从变量结尾开始删除最长匹配的word
#替换操作
${变量/pattern/string} 用string代替第一个匹配的pattern
${变量//pattern/string} 用string代替所有的pattern
mingyan="goodgoodstudy,daydayup!"
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan}
goodgoodstudy,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${#mingyan}
23
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan:4}
goodstudy,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan:4:9}
goodstudy
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan#good}
goodstudy,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan##good}
goodstudy,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan##study}
goodgoodstudy,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan##goodgoodstudy}
,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan%up!}
goodgoodstudy,dayday
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan/good/hao}
haogoodstudy,daydayup!
shuai@shuais-MacBook-Pro batchRename % echo ${mingyan//good/hao}
haohaostudy,daydayup!
获取字符串的长度
string-name,#加字符串变量名
#!/bin/bash
str="shenshuai89@qq.com"
echo ${#str}
字符串拼接合并
Shell 中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接
#!/bin/bash
email="shenshuai89@qq.com"
username="北鸟南游"
str1=$username$email #中间不能有空格
str2="$username $email" #如果被双引号包围,那么中间可以有空格
str3=$username": "$email #中间可以出现别的字符串
str4="$username: $email" #这样写也可以
str5="${username}Script: ${email}index.html" #这个时候需要给变量名加上大括号
echo $str1
echo $str2
echo $str3
echo $str4
echo $str5
字符串截取
从指定位置开始截取
这种方式需要两个参数:除了指定起始位置,还需要截取长度${string: start :length},length 是要截取的长度(省略的话表示直到字符串的末尾)
#!/bin/bash
email="shenshuai89@qq.com"
echo ${email: 4: 7}
# 输出shuai89
从右侧开始计数
从字符串的右边开始计数${string: 0-start :length},从右侧计数,要从1开始
#!/bin/bash
email="shenshuai89@qq.com"
echo ${email: 0-14: 7}
从指定字符(子字符串)开始截取
这种截取方式无法指定字符串长度,只能从指定字符(子字符串)截取到字符串末尾。Shell 可以截取指定字符(子字符串)右边的所有字符,也可以截取左边的所有字符。
- 使用 # 号截取右边字符 ${string#*chars}
- 使用 号截取右边字符 ${string%chars}
如果有多个符号条件,希望直到最后一个指定字符(子字符串)再匹配结束,那么可以使用##或者**#! /bin/bash
email="shenshuai89@qq.com"
echo ${email#*shuai}
echo ${email%shuai*}
# 89@qq.com
# shen
#! /bin/bash
email="shenshuai89@qq.com"
echo ${email#*sh}
echo ${email##*sh}
# enshuai89@qq.com
# uai89@qq.com
数组
定义数组,使用()
Shell 中,用括号( )来表示数组,数组元素之间用空格来分隔 ```bash!/bin/bash
arr=(1 2 3) echo “${arr[2]}”
Shell 是弱类型的,它并不要求所有数组元素的类型必须相同
arr=(23 34 ‘defineArray’) echo “${arr[2]}”
⚠️注意:赋值号=两边不能有空格,必须紧挨着数组名和数组元素
<a name="JOCR4"></a>
### 数组增加元素
shell定义的数组长度是不固定的,定义之后还可以增加元素。
```bash
#!/bin/bash
# 给数组增加元素
names=('sam' 'shenshuai')
names[2]='beiniaonanyou'
echo ${names[2]}
# 获取数组中的所有元素${arr[*]}
echo ${names[*]}
# 获取数组长度 ${#arr[*]}
echo ${#names[*]}
数组拼接
将两个数组连接成一个数组,利用@或*,将数组扩展成列表,然后再合并到一起
#!/bin/bash
arr1=(1 3 5)
arr2=('string' 'number')
arrAll=(${arr1[*]} ${arr2[*]})
echo ${arrAll[*]}
删除数组元素
shell使用 unset 关键字来删除数组元素 unset array_name[index]
#!/bin/bash
unset arrAll[2]
echo ${arrAll[*]}
# 删除数组全部
unset arrAll
echo ${arrAll[*]}
read获取输入
read用来从标准输入中读取数据并赋值给变量。默认就是从键盘读取用户输入的数据;
语法: read [options] [values]
-p prompt | 显示提示信息,提示内容为 prompt。 |
---|---|
-r | 原样读取(Raw mode),不把反斜杠字符解释为转义字符 |
-s | 静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的 |
-n num | 读取 num 个字符,而不是整行字符。 |
#!/bin/bash
read -p "input your name age > " name age
echo "名字:$name"
echo "年龄:$age"
运算
(())
双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,
((表达式)):将数学运算表达式放在(())中
echo $((1+1))
echo $((2-1))
echo $((2*2))
echo $((2/1))
echo $((8<3))
let
let的作用和(())类似,都是对数据进行运算。
两者都是只能处理整数,不能处理小数或字符串。
a=10 b=20
let c=a+b
echo c
expr
expr运算,数字和运算符号中间要有空格,否则会被当作字符串输出。
乘号*要做转义处理
#!/bin/bash
# 两个数字运算,中间要留空格,否则会当作完整字符串输出
expr 1 + 1 #2
expr 5 - 2 #3
expr 2 \* 7 #14
expr 5 / 2 #2
条件语句
if else
read a
read b
if (($a == $b))
then
echo "a==b"
else
echo "a!=b"
fi
if elif else
echo 'input age number'
read age
if (($age <=2));then echo '婴儿';
elif (($age >=3 && $age <=8 )); then
echo '幼儿';
elif (($age >=9 && $age <=17)); then
echo '少年';
elif (( $age >=18 && $age <= 25))
then echo '成年'
elif (( $age >= 26 && $age <= 40))
then echo '青年'
elif (($age>=41 && $age <=60))
then echo '中年'
else
echo '老年'
fi
printf 'input integer number: '
read num
if (($num == 1)); then echo 'Monday';
elif (($num ==2));then echo 'Tuesday';
elif (($num ==3));then echo 'Wednesday';
elif (($num ==4));then echo 'Thursday';
elif (($num==5)); then echo 'Friday';
elif (($num==6)); then echo 'Saturday';
elif (($num==7)); then echo 'Sunday';
else 'error';
fi
case
printf "input integer number: "
read num
case $num in
1)
echo "Monday";;
2)
echo "Tuesday";;
3)
echo "Wednesday";;
4)
echo "Thursday";;
5)
echo "Friday";;
6)
echo "Saturday";;
7)
echo "Sunday";;
*)
echo "error"
esac
while
i=1
sum=0
while ((i<=100))
do
((sum += i))
((i++))
done
echo "result: $sum"
sum=0
echo "请输入您要计算的数字,按 Ctrl+D 组合键结束读取"
while read n
do
((sum += n))
done
echo "sum result: $sum"
for
sum=0
for ((i=0; i<=100; i++))
do
((sum += i))
done
echo "result sum: $sum"
break continue
break
使用 while、until、for、select 循环时,如果想提前结束循环,可以使用 break 或者 continue 关键字。
#!/bin/bash
sum=0
while read n; do
if ((n>0));then
((sum+=n))
else
break
fi
done
echo "sum is $sum
Shell 中的 break 和 continue 能够跳出多层循环;break n或者continue n,默认跳出当前循环
#!/bin/bash
i=0
while ((++i)); do
j=0
while ((++j)); do
if ((i>4)); then
break 2
fi
if ((j>4));then
break
fi
printf "%-4d" $((i*j))
done
printf "\n"
done
第7行表示跳出2层循环;
break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。
continue
跳出当前循环,100以内的值相加,使用ctrl+d结束
#!/bin/bash
sum=0
while read n; do
if ((n<1 || n>100)); then
continue
fi
((sum+=n))
done
echo "sum=$sum"
不跳出循环
printf中 %d 的意思是按照整数格式输出后面的第一个参数的值。 printf中 %-4d的意思:输出一个int型数,4位宽度,左对齐。后面若还有输出项时,n的输出至少占4位,不足4位时,后面补空格到4位;若超过4位时,按实际宽度输出n的值。
#!/bin/bash
for ((i=1; i<=9; i++)); do
for ((j=1; j<=9; j++)); do
printf "%d*%d=%-4d" $i $j $((i*j))
done
printf "\n"
done
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
2*1=2 2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*1=4 4*2=8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 6*7=42 6*8=48 6*9=54
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
条件添加,退出多层循环
for ((i=1; i<=9; i++)); do
for ((j=1; j<=9; j++)); do
if ((i<j)); then
printf "\n"
continue 2
fi
printf "%d*%d=%-4d" $i $j $((i*j))
done
printf "\n"
done
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
select in
select in是增强交互,可以将in后的值按照编号显示输出。用户选择不同的编号,执行不同的操作。
select in 是 Shell 独有的一种循环,非常适合终端(Terminal)这样的交互场景。
#!/bin/bash
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
do
echo $name
done
echo "You have selected $name"
⚠️注意,select 是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到 break 语句,或者按下 Ctrl+D 组合键才能结束循环。
select in通常和case in一起使用,用户选择不同序号执行不同程序。
echo "which is your love os?"
select name in "Linux" "windows" "mac" "unix" "android"
do
case $name in
"Linux")
echo "Linux是一个类UNIX操作系统,它开源免费,运行在各种服务器设备和嵌入式设备。"
break;;
"windows")
echo "Windows是微软开发的个人电脑操作系统,它是闭源收费的。"
break;;
"mac")
echo "Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。"
break;;
"unix")
echo "UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。"
break;;
"android")
echo "Android是由Google开发的手机操作系统,目前已经占据了70%的市场份额。"
break;;
*)
echo "输入错误,请重新输入"
esac
done
echo "you have selected $name"
函数
Shell 函数的本质是一段可以重复使用的脚本代码,使用时直接调用即可。
shell函数语法
function name() {
statements
[return value]
}
定义一个函数,计算所有参数的和
#!/bin/bash
function getsum(){
local sum=0
for n in $*
do
((sum+=n))
done
return $sum
}
getsum 10 20 30
echo $?
$*表示所有参数,$?表示函数的退出状态(返回值)
参考文档:
c语言编程
http://c.biancheng.net/view/706.html
阿里云课堂
https://edu.aliyun.com/course/155/lesson/list?utm_content=m_1000297219
shell编程范例
https://tinylab-1.gitbook.io/shellbook/01-chapter1