简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务
Shell 脚本
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
日常所说的 shell 通常都是指 shell 脚本,但其实 shell 和 shell script 是两个不同的概念。
Shell 解释器
Shell 编程只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。
在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。
Hello,Shell
我们第一个 Shell 也从 Hello,World! 开始吧!面向world 编程嘛!!
在自己练习的目录下,新建 hello.sh 文件敲入下面内容,并修改权限为可执行。
#!/bin/bash
echo "Hello,World! My Shell!"
[root@wang shell]# vim hello.sh
[root@wang shell]# chmod u+x hello.sh # 修改改可执行文件
[root@wang shell]# ./hello.sh # 执行脚本
Hello,World! My Shell! # 显示输出内容
[root@wang shell]#
Shell 变量
定义变量时,变量名不加美元符号($),如:
your_name="zhangpeng"
注意,变量名和等号之间不能有空格。同时,变量名的命名须遵循如下规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线 _。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
简单使用
[root@wang shell]# name=zhangpeng
[root@wang shell]# echo $name
zhangpeng
[root@wang shell]# echo ${name} # 定义变量边界
zhangpeng
[root@wang shell]# echo my name is ${name} # 有了边界 ${name}ToUpper 后面有其他字母也可能识别
my name is zhangpeng
常量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
pi=3.14
readonly myUrl
pi=5
[root@wang shell]# pi=3.14
[root@wang shell]# readonly pi # 设置为只读
[root@wang shell]# pi=5
bash: pi: readonly variable
[root@wang shell]#
删除变量
使用 unset 命令可以删除变量
unset varname
[root@wang shell]# age=34
[root@wang shell]# echo $age
34
[root@wang shell]# unset age # 设置变量无效 删除变量
[root@wang shell]# echo $age # 再次查看 没有结果
[root@wang shell]#
变量类型
shell 中有三种变量:
1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
3) shell 变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
字符串
字符串应该是多数程序中最常用的类型了,shell 也不例外!
shell 中使用单引号和双引号都可以表示字符串,甚至不使用引号也可以。
注意:shell 单引号和双引号使用上还是有区别的
[root@wang shell]# name=zhangpeng # 没使用双引号的字符串
[root@wang shell]# echo $name
zhangpeng
[root@wang shell]# echo 'my name is $name' # 单引号中引用变量无效
my name is $name
[root@wang shell]# echo "my name is $name" # 双引号中可以引用变量
my name is zhangpeng
[root@wang shell]# echo 'my name is' $name # 单引号可以拼接变量 这样是可以的
my name is zhangpeng
[root@wang shell]#
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
双引号的优点:
- 双引号里可以有变量
- 双引号里可以出现转义字符
字符串长度
#井号 可以求长度
[root@wang shell]# name=zhangpeng
[root@wang shell]# echo ${#name}
9
截取子串
${name:start:count}
[root@wang shell]# echo ${name:0} # 从0开始截取到结尾
zhangpeng
[root@wang shell]# echo ${name:1}
hangpeng
[root@wang shell]# echo ${name:3:1} # 从3开始截取到1个字符
n
替换
[root@wang shell]# echo ${name/n/x} # 替换第一个匹配字符串
zhaxgpeng
[root@wang shell]# echo ${name//n/x} # 两个斜杠替换所有的匹配字符串
zhaxgpexg
[root@wang shell]#
删除
[root@wang shell]# name=Test.java
[root@wang shell]# echo ${name%.java} # 以.java 结尾则删除,否则原样输出
Test
[root@wang shell]#
${parameter} 返回变量$parameter的内容 ${#parameter} 返回变量$parameter的内容长度,适用于特殊变量 ${parameter:offest} 返回变量$parameter中,从offest位置后到结尾的字符串 ${parameter:offest:length} 返回变量$parameter中,从offest位置后提取长度为length的字符串 ${parameter#word} 返回变量$parameter中,开头开始删除最短匹配的word字符串 ${parameter##word} 返回变量$parameter中,开头开始删除最长匹配的word字符串 ${parameter%word} 返回变量$parameter中,结尾开始删除最短匹配的word字符串 ${parameter%%word} 返回变量$parameter中,结尾开始删除最长匹配的word字符串 ${parameter/word/strinng} 使用string替换第一个匹配的word ${parameter//word/strinng} 使用string替换匹配的所有的word
注释
以 # 开头的行就是注释,会被解释器忽略。
通过每一行加一个 # 号设置多行注释,像这样:
#--------------------------------------------
# 这是一个注释
#--------------------------------------------
多行注释
多行注释还可以使用以下格式:
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
接收输入
read varname # 程序阻塞,等待用户输入,输入的值,赋值给 varname 变量
1 echo "请输入您的年龄:"
2 read age
3 echo "请输入您姓名:"
4 read name
5 echo "您输入的姓名是${name},年龄是${age}"
算术运算
[root@wang shell]# num1=3
[root@wang shell]# num2=4
[root@wang shell]# expr $num1+num2
3+num2
[root@wang shell]# expr $num1+$num2
3+4
[root@wang shell]# echo $[num1-num2]
-1
[root@wang shell]# echo $[num1+num2]
7
[root@wang shell]# echo $((num1+num2))
7
let 运算符
echo "请输入第一个数:"
read num1
echo "请输入第二个数:"
read num2
let result=num1+num2
echo "$num1+$num2=$result"
if - else 语句
echo "请输入您的考试成绩:"
read score
if [ $score -ge 60 ]
then echo "恭喜,及格了!"
else
echo "下次补考吧!";
fi
if-elif-else
echo "请输入您的考试成绩:"
read score
if [ $score -ge 90 ]
then echo "优秀"
elif [ $score -ge 80 ]
then echo "良好"
elif [ $score -ge 60 ]
then echo "一般"
else
echo "差评"
fi
case
case $1 in
1) #必须带右边括号
echo "星期一"
;; #相当于break
2)
echo "星期二"
;;
*) #相当于default
echo "输入错误"
;;
esac
合并
echo "请输入今天星期几"
read week
case $week in
1 | 2 | 3 | 4 | 5)
echo "工作!"
;;
6 | 7)
echo "休息"
;;
*)
echo "输入错误"
;;
esac
for
for i in 1 3 5 7 9
do
echo $i
done
双括号简化
sum=0
for((i=1;i<=100;i++))
do
let sum=sum+i
done
echo "1+2+3+..+100=$sum"
while
i=1
sum=0
while ((i<=100))
do
let sum+=i;
let i++;
done
echo "sum=$sum"
应用
根据条件创建目录
for (( i=0;i<10;i++ ))
do
if [ $(($i%2)) -eq 0 ]
then mkdir user$i
fi
done
echo "目录创建成功"
根据当前日期创建目录
y=$(date +%Y);
m=$(date +%m);
d=$(date +%d);
dir="${y}/${m}/${d}";
mkdir -p $dir;
echo "${dir}创建成功!"
批量删除目录
for f in /root/test/*
do
if [[ $f == *a* ]]
then rm -rf $f
fi
done
模仿 ls 命令列出当前目录下文件的功能,使用 shell 脚本实现我们自己的 list 列表功能
第一步:vi myls.sh
1 for f in * # 当前目录下所有的文件集合
2 do
3 echo "${f}"
4 done
默认使用方式:需要使用 ./ 的方式调用
[root@wang opt]# ./shell/ls.sh ## 可以实现列出pwd 当前目录下文件
apache-tomcat-9.0.52
apache-tomcat-9.0.52.tar.gz
dump.rdb
mydir
如果想在任何地方直接调用shell 脚本,可以把文件拷贝到 /usr/local/bin 即可
[root@wang shell]# cp myls.sh /usr/local/bin
[root@wang shell]# myls.sh ### 再次直接调用 ,可以了
add.sh
case0.sh
case2.sh
最后,再重命名,把myls.sh 重名为 myls
[root@wang bin]# mv myls.sh myls
[root@wang bin]# ls ## 系统命令
dump.rdb redis1.conf redis3.conf redis-check-aof redis-cli redis-sentinel sentinel.conf
myls redis2.conf redis-benchmark redis-check-rdb redis.conf redis-server
[root@wang bin]# myls ## 自己的命令
dump.rdb
myls
redis1.conf
redis2.conf