shell是什么?
Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁;
Shell既是一种命令语言,又是一种程序设计语言;
Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问 Linux 内核的服务
shell脚本有sh、bash、ksh、csh、zsh等等,不同的shell脚本有自己的特点,但用法基本上是差不多的,Mac自带shell,可以用cat /etc/shells
去查看,文章主要围绕bash展开。
shell脚本
一般文件后缀是.sh形式的。
哪些人需要学习shell呢?
- Linux运维工程师:编写Shell程序进行服务集群管理
- Python和Java程序员:编写Shell脚本程序或者是服务器的维护,比如编写一个定时备份数据库的脚本
- 大数据程序员:编写Shell程序来管理集群
- 前端程序员:了解shell可以更好的进行服务端开发操作
shell脚本能做什么呢?
- 将一些复杂的命令简单化(比如我们提交一次代码可能需要很多步骤,但是可以用Shell简化成一步);
- 解决很多重复性操作(比如多次修改相同的文件内容);
- 自动打包、编译、发布等功能;
所以学会使用shell可以帮助我们大大的提高开发效率.
shell编写
第一行一般是这样:(指定脚本解释器)
#!/usr/bin/php
#!/usr/bin/env python3
#!/usr/bin/env bash
#!”是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行/env是系统的PATH目录中查找;告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器
运行shell脚本
方式1
sh demo.sh
方式2
chmod +x demo.sh // 设置 demo.sh可执行权限
./demo.sh // 执行demo.sh
我们来编写一个简单的demo
// demo1.sh
#!/usr/bin/env bash // 从系统path中寻找指定脚本的解释程序
echo "hello, world"
// 执行
控制台执行bash demo1.sh
// 输出:hello, world
常见语法
变量
已经定义过的变量,使用时在前面添加$,变量名外的花括号是可选的,加不加都行,建议使用第二种形式
命名
name="qiao"
使用
echo $name
echo ${name}
基础语法
- 定义变量: 变量名=变量值,等号两侧不能有空格,变量名一般习惯用大写
- 删除变量: unset 变量名
- 声明静态变量: readonly 变量名,静态变量不能unset
- 使用变量:$变量名
// 访问变量的语法形式为:${var} 和 $var
echo $myName
echo ${myName}
// 删除变量
echo ${变量名}
变量命名规则
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
- 中间不能有空格,可以使用下划线_
- 不能使用标点符号
- 不能使用 bash 里的关键字
变量类型
- 局部变量 : 仅在某个脚本内部有效的变量。不能被其他的程序和脚本访问
- 环境变量: 对当前 shell 会话内所有的程序或脚本都可见的变量。跟创建局部变量类似,但使用的是
export
关键字,shell 脚本也可以定义环境变量;
位置参数变量
基本语法
- $n :$1 代表命令本身、$1- 9 代 表 第 1 到 9 个 参 数 , 10 以 上 参 数 用 花 括 号 , 如 9 代表第1到9个参数,10以上参数用花括号,如 9代表第1到9个参数,10以上参数用花括号,如{10}
- $* :命令行中所有参数,且把所有参数看成一个整体
- $@ :命令行中所有参数,且把每个参数区分对待
- $# :所有参数个数
注释
以“#”开头的行就是注释,会被解释器忽略。sh里没有多行注释,只能每一行加一个#号
字符串
字符串可以用单引号,也可以用双引号,也可以不用引号。Shell中常用的数据类型字符串和数字。
先来看个demo
name="qiao"
echo "my name is $name"
// 输出 my name is qiao
字符串可以使用单引号和双引号,单引号中不能包含单引号,即使转义单引号也不次那个,双引号则可以,双引号也可以使用字符串.
字符串操作
拼接字符串
name="qiao";
age="26"
echo $name $age
echo $name$age
获取字符串长度
echo ${#name}
截取字符串
echo ${name:0:2}
数组
Shell中,用括号来表示数组,数组元素用"空格"符号分割开,定义数组的一般形式为
age=(age1 age2 age3)
// 也可单独定义数组的各个值:
ary[0]=age1
ary[1]=age2
ary[3]=age3
看个demo
names=("zhang" "san" "zi")
echo ${names[0]}
echo ${names[2]}
echo ${names[@]} # @可以获取数组中的所有元素
// 输出
zhang
zi
zhang san zi
读取数组
格式
${数组名[下标]}
echo ${age[0]}
// 使用@符号可获取数组中的所有元素
echo ${name[@]}
获取数组的长度
# 获取数组元素的个数
length=${#age[@]}
echo $length
# 或者
length=${#age[*]}
echo $length
# 取得数组单个元素的长度
lengthn=${#age[n]}
echo $length
shell参数传递
执行Shell脚本时,可以向脚本传递参数,在Shell中获取这些参数的格式为$n,即$1,$2…,
// demo2.sh
echo "第一个参数是:$1"
echo "第一个参数是:$2"
echo "第一个参数是:$3"
// 执行
bash demo2.sh 1 2 3
// 输出
第一个参数是:1
第一个参数是:2
第一个参数是:3
特殊字符处理参数:
-
$#:传递脚本的参数个数
-
$*:显示所有的参数
-
$@:返回所有参数
-
$-:显示Shell使用的当前选项
-
$?:退出的状态,0表示没有错误,其他则表示有错误
运算
算数运算
本身bash是不支持简单的数学运算的,可以借助其他命令来完成,例如awk和expr,expr最常用。expr是一款表达式计算工具,使用它能完成表达式的求值操作。算术运算符包括:+ - × / % = == !=
看个demo
// demo.sh
val=`expr 2 + 2`
echo $val
// 执行 bash demo.sh
// 输出4
注意
- 运算符两边需要空格,且使用的是反引号
关系运算符
关系运算只支持数字,不支持字符串,除非字符串的值是数字
常见关系运算符
- -eq:是否相等
- -ne:是否不等
- -gt:大于
- -lt:小于
- -ge:大于等于
- -le:小于等于
看个demo
// demo.sh
a=4
b=3
if [ $a -eq $b ]
then
echo "相等"
else
echo "不等"
fi
// bash demo.sh
// 输出 不等
布尔运算
- !:非
- -o:或
- -a:与
逻辑运算符
- &&:逻辑与
- ||:逻辑或
字符串运算符
- =:相等
- !=:不等
- -z:字符串长度是否为0,为0返回true [ -z $a ]
- -n:字符串长度是否为0,不为0返回true[ -n $a ]
- str:字符串是否为空,不为空返回true [ $a ]
文件测试运算符
属性 | 描述 | 写法 |
---|---|---|
-b | 检测文件是否为块设备文件 | [ -b $file ] |
-c | 检测文件是否为字符设备文件 | [ -c $file ] |
-d | 检测文件是否为目录 | [ -d $file ] |
-f | 检测文件是否为普通文件 | [ -f $file ] |
-g | 检测文件是否设置了SGID位 | [ -g $file ] |
-k | 检测文件是否设置了粘着位 | [ -k $file ] |
-p | 检测文件是否是有名管道 | [ -p $file ] |
-u | 检测文件是否设置了SUID位 | [ -u $file ] |
-r | 检测文件是否可读 | [ -r $file ] |
-w | 检测文件是否可写 | [ -w $file ] |
-x | 检测文件是否可执行 | [ -x $file ] |
-s | 检测文件大小是否大于0 | [ -s $file ] |
-e | 检测文件是否存在 | [ -e $file ] |
看个demo
// demo.sh
file="/Users/用户名/Desktop/shell-study/demo.sh"
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
if [ -r $file ]
then
echo "可读"
else
echo "不可读"
fi
if [ -w $file ]
then
echo "可写"
else
echo "不可写"
fi
// bash demo.sh
// 输出
文件存在
可读
可写
流程判断
条件
#!/usr/bin/env bash
a=1
b=2
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a大于 b"
elif [ $a -lt $b ]
then
echo "a小于 b"
else
echo "没有符合的条件"
fi
for循环
// 写法1
for index in 1 2 3 4 5; do
echo "index="$index
done
// 写法2
for ((i=0; i<5; i++)); do
echo "i="$i
done
while 语句
val=1
while(( $val<=5 ))
do
echo $val
let "val++"
done
case
格式:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
看个demo
#!/usr/bin/env bash // 从系统path中寻找指定脚本的解释程序
echo "输入1 2 3任意一个数字"
read num
case $num in
1)echo "输入了1"
;;
2)echo "输入了2"
;;
3)echo "输入了3"
;;
*)echo "输入的值不是1 2 3"
;;
esac
// 输出
bash demo3.sh
输入1 2 3任意一个数字
1
输入了1
bash demo3.sh
输入1 2 3任意一个数字
2
输入了2
bash demo3.sh
输入1 2 3任意一个数字
3
输入了3
bash demo3.sh
输入1 2 3任意一个数字
5
输入的值不是1 2 3
函数
函数定义
自定义函数可使用或不使用function关键字,指定了return值则返回这个值,没有return语句则以最后一条运行结果作为返回值
看个demo
function fn(){
echo "hello world"
}
// 或者
fn(){
echo "hello world"
}
函数调用
函数名
fn
函数参数
调用函数时可以传入参数,函数内部使用;函数本身是一个命令,所以只能通过$?来获得这个返回值
#!/usr/bin/env bash // 从系统path中寻找指定脚本的解释程序
function add(){
num=0;
for((i=1;i<=$#;i++));
do
num=`expr $i + $num`
done
return $num
}
add 1 2 3 4 5 6 7 8 9 10
a=$?
echo $a
// bash demo.sh
// 输出: 55
输入输出重定向
使用 > 可以将echo结果写入指定文件,这就是一种输出重定向,重定向主要有以下几种:
写法 | 描述 |
---|---|
command > file | 输出重定向至文件file |
command < file | 输入重定向至文件file |
command >> file | 输出以追加的方式重定向至文件file |
n > file | 将文件描述符为n的文件重定向至文件file |
n >> file | 将文件描述符为 n 的文件以追加的方式重定向到文件file |
n >& m | 将输出文件 m 和 n 合并 |
n <& m | 将输入文件 m 和 n 合并 |
<< tag | 将开始标记 tag 和结束标记 tag 之间的内容作为输入 |
常见命令
echo
用于字符串的输出
echo "hello, world"
// 输出hello, world
// 输出含变量的字符串:
name = word
echo "hello, \"${name}\""
// 输出hello, "word"
// 输出含换行符的字符串
echo "name\nage"
// 输出 name\nage
echo -e "name\nage" # -e 开启转义
# 输出
# name
# nage
// echo $PATH 获取系统里所有可以被直接执行程序的路径
解析转义字符
-e
参数使得 echo
可以解析转义字符
echo -e "hello \n world" # 如果不添加-e则会原样输出,添加了-e输出则会换行
使用反引号可以显示命令执行的结果,如date、pwd
echo `pwd`
echo `date`
printf
格式化输出字符串,默认情况下,printf 不会像echo自动添加换行符,如果需要换行可手动添加 \n
export
export 变量名=变量值,将Shell变量输出为环境变量
source
source 配置文件路径,让修改后的配置信息立即生效
test
检查某个条件是否成立,可以进行数值、字符、文件三方面的测试
// demo.sh
a=20
b=23
if test a == b
then
echo "相等"
else
echo "不等"
fi
// bash demo.sh
// 输出:不等
grep
擅长查找功能
写法
grep [OPTIONS] PATTERN [FILE...]
这里的模式,要么是字符(串),要么是正则表达式
常见参数
参数 | 描述 |
---|---|
-c | 仅列出文件中包含模式的行数 |
-i | 忽略模式中的字母大小写 |
-l | 列出带有匹配行的文件名 |
-n | 在每一行的最前面列出行号 |
-v | 列出没有匹配模式的行 |
-w | 把表达式当做一个完整的单字符来搜寻,忽略那些部分匹配的行 |
看个例子
// 文件路径 filePath="/Users/用户名/Desktop/shell-study/file.js"
// 查找并打印包含"list"的行
grep "list" ${filePath}
// 忽略大小写搜索(-i)
grep -i "list" ${filePath}
// 统计字符串出现的次数(-c)
grep -c "show" ${filePath} #17
grep -n "show" ${filePath}
-n 可以列出匹配的字符串所在行号以及所在行内容
// 高亮显示匹配内容(--color)
grep --color "list" ${filePath}
// 双重条件匹配 匹配当前目录中包含float的文件并高亮
ls *.html | grep --color "float"
总结
-
单引号字符串的限制:
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
单引号字串中不能出现单引号(对单引号使用转义符后也不行)
-
双引号
双引号里可以有变量
双引号里可以出现转义字符
-
变量
变量只能由大小写字母,数字和下划线组成。
变量名称不能以数字开头;变量赋值等号两边不能有空格
变量可以存储数字类型或者字符串类型
字符串的变量可以用单引号或者双引号括起来
GitHub代码参考链接:https://github.com/qiaochunmei/shell-study