# 扎好马步
- 双引号里面可以写变量$x,单引号会将$x 当成字符串
# 自定义变量
# 变量的定义
变量是由任何字母、数字和下划线组成的字符串,且不能以数字开头
严格区分大小写
变量、等号、值中间不能出现任何空格
申明的变量默认都会按照字符串来定义,也就是说可以不加引号,但如果字符串内容有空格那么需要使用单双引号定义
# 变量的引用
直接$var 即可
#!/bin/bash
#
var1=hello
var2=‘hello world’
echo $var1
echo $var2
# 位置变量
当一条命令或者脚本执行时,后面可以跟很多参数,我们使用位置参数变量来表示这些参数
- 位置变量存在与 shell 当中可以直接使用
# 位置变量参数
位置参数变量 | 含义 |
---|---|
$n | n 为数字,$0代表脚本本身,$1 ~$9代表1~9个参数。10以上的参数需要用打括号包含,如${10} |
$@ | 命令行所有参数,但每个参数区别对待 |
$* | 命令行所有参数,所有参数视为一个整体 |
$# | 参数个数 |
$$ | 输出最近进程的 pid |
#!/bin/bash
#
echo "第一个参数: $1"
echo "第二个参数: $2"
echo $*
echo $@
echo $#
function add
{
value=`expr $1 + $2`
echo $value
}
add $1 200
sh var.sh 1 2 3 输出结果
第一个参数: 1
第二个参数: 2
1 2 3
1 2 3
3
201
# 环境变量
# 环境变量的定义
Linux 是一个多租户的操作系统,针对不同的用户会有一个专有的运行环境
不同用户的专有环境就是一组默认环境变量的组合(简单理解)
环境变量默认使用大写定义
# 环境变量的分类
对所有用户生效的环境变量 /etc/profile
对特定用户生效的环境变量 ~/.bashrc 或者~/.bash_profile (没有该文件的话可以自行建立)
临时有效的环境变量 脚本或命令使用 export
# 系统默认的环境变量
- 通过命令行 $环境变量 可以输出
环境变量 | 含义 |
---|---|
PATH | 命令搜索的路径 |
HOME | 用户家的目录路径 |
LOGNAME | 用户登录名 |
PWD | 当前所在路径 |
HISTFILE | 历史命令的保存文件 |
HISTSIZE | 历史命令保存的最大行数 |
HOSTNAME | 主机名 |
SHELL | 用户当前使用的 SHELL |
PS1 | 一级命令提示符 |
TIMEOUT | 用户和系统交过程的超时值 |
IFS | 系统输入分隔符(默认空格或者 tab 或者换行符\n) |
OFS | 系统输出分隔符 |
#!/bin/bash
#
echo $HOME
echo $PWD
# 管道
# 管道的定义
将上一个命令的输出作为下一个命令的输入,使用 | 连接两个命令。从某种意义上来说,是重定向的简易实现
以下为找出 brew 包中所有名称带有 open 的 / 列出 brew 包中所有名称带有 open 的行数
brew list | grep open
brew list | grep open | wc -l
# 退出状态码
# 退出状态码的定义
所有的 shell 命令都使用退出状态码来告知 shell 它已经执行完毕
退出状态码是以上一条指令的返回结果为准
退出状态码是一个 0 ~ 255 的整数值
-Linux 提供了一个$?来捕获退出状态码的值
# 退出状态码含义(记住 0 和非 0 即可)
状态码 | 含义 |
---|---|
0 | 命令成功结束 |
1 | 一般性未知错误 |
2 | 不适合的 shell 命令 |
126 | 命令不可执行 |
127 | 没找到命令 |
128 | 无效的退出参数 |
128+x | 与 Linux 命令 x 相关的严重错误 |
130 | 通过 ctrl+c 终止的命令 |
255 | 正常范围之外的退出码 |
asd
echo $? // 127
#!/bin/bash
#
date
if [ $? -eq 0 ]; then
echo 'success'
else
echo 'failed'
fi
# 改变退出状态码的 exit 命令
- exit 会直接导致退出脚本
// exit $exit + 数值
exit $exit 48
#!/bin/bash
#
date123
if [ $? -eq 0 ]; then
echo 'success'
else
echo 'failed'
exit 25
fi
echo $?
PS:退出脚本后输出 echo $? 显示 25
# if-then / if-then-else
# 语法
if 后面一定有空格
if command | condition 后面添加 &> /dev/null,将 command | condition 重定向到垃圾桶中,不会改变返回状态码,也不会在 shell 中输出 command | condition 产生的值
if command | condition &> /dev/null
then
conmmands
else
conmmands
fi
#!/bin/bash
#
if echo '123' &> /dev/null
then
echo 'success'
fi
不会输出 123
# 嵌套 if
- if 和 then 放在一排必须有;分割
# 语法
if command | condition
then
conmmands
elif command | condition
then
conmmands
fi
if command | condition;then
conmmands
elif command | condition;then
conmmands
fi
# if 的条件判断
- 条件判断的判断内容必须写在[]里面,并且[ $1, $2 ]开始和结尾要留有空格(运算符前后必须有空格)
#!/bin/bash
#
if [ $1 -eq $2 ]; then
echo 'success'
fi
# 数值比较
数值比较 | 含义 |
---|---|
n1 -eq n2 | n1 === n2 ? true : false |
n1 -ne n2 | n1 !== n2 ? true : false |
n1 -gt n2 | n1 > n2 ? true : false |
n1 -ge n2 | n1 >= n2 ? true : false |
n1 -lt n2 | n1 < n2 ? true : false |
n1 -le n2 | n1 <= n2 ? true : false |
# 字符串比较
字符串比较时候和 js 不同,没有===这种说法
输入< >符号比较的时候需要转义,因为这两个符号在 Linux 中表示重定向
#!/bin/bash
#
a='qq'
b='vv'
if [ $a \< $b ]; then
echo 'equal'
else
echo 'not equal'
fi
字符串比较 | 含义 |
---|---|
str1 = str2 | 相等比较 |
str1 != str2 | 不等比较 |
str1 < str2 | str1 < str2 为 true (比较第一个字母的字母表的顺序,越前越大) |
str1 > str2 | str1 > str2 为 true (比较第一个字母的字母表的顺序,越前越大) |
-n str1 | str1 长度不为 0 则返回 true |
-z str1 | str1 长度为 0 则返回 true |
PS:-n 和 -z 是检查字符串是否定义的,值得注意的是,没有定义的值检查必须加双引号
#!/bin/bash
#
b='vv'
if [ -n "$a" ]; then
echo 'not kong'
else
echo 'kong'
fi
# 文件比较
文件比较 | 含义 |
---|---|
-d file | file 是否为目录 |
-f file | file 是否为文件 |
-e file | file 是否存在 |
-r file | file 是否可读 |
-w file | file 是否可写 |
-x file | file 是否可执行 |
-s file | file 存在且非空 |
file1 -nt file2 | file1 比 file2 更新为真 |
file1 -ot file2 | file1 比 file2 更旧为真 |
if [ -f index.js ];then echo 1;else echo 2; fi
# if 的复合条件测试
if [ condition1 ] && [ condition2 ]
then
conmmands
else
conmmands
fi
if [ condition1 ] && [ condition2 ]
then
conmmands
else
conmmands
fi
#!/bin/bash
#
a=5
b=1
c=3
d=4
if [ $a -lt $b ] && [ $c -eq $d ]; then
echo 'yes'
else
echo 'no'
fi
PS:注意&&是在两个[]之间的而不是写在[]里面
# if-then 中使用双括号
不止 if-then 中使用,shell 脚本中也可以使用双括号
使用双括号可以进行算术运算
双括号中,变量引用可以加$也可以不加(这里注意,单独的双括号是不能加$使用变量的,但是在条件语句后面的就可以)
num=10
while (($num < 20 )); do # 这里都可以
echo 'number is' $num
((num++)) # 这里不能够加
done
运算符前后可以有空格也可以没有
双括号不止可以用于 if,还可以用于 for、while 等循环结构中
多个运算表达式使用逗号分割
以下是传统写法和双括号写法
if [ -f file ]
then
conmmands
fi
if ((expression))
then
conmmands
fi
示例
#!/bin/bash
#
c=3
d=4
if ((d < c)); then
echo 'yes'
else
echo 'no'
fi
a=10
((a++,a=a-10))
echo $a
# 以下三种方式是等价的
if (($1 > $2 && $3 > $2)); then
echo 'yes'
else
echo 'no'
fi
if [ $1 > $2 ] && [ $3 > $2 ] ; then
echo 'yes'
else
echo 'no'
fi
if [ $1 ] >$2 && [ $3 ] >$2; then
echo 'yes'
else
echo 'no'
fi
可用的运算符
运算符 | 含义 |
---|---|
value++/-- | 后增/减 |
++/--value | 先增/减 |
! | 逻辑求反 |
== | 相等 |
>/< | 大于/小于 |
>=/<= | 大于等于/小于等于 |
&& | 逻辑与 |
|| | 逻辑或 |
# if-then 中使用双方括号
变量名必须引用$
变量之间可以不加空格但是[[]]中首位必须加空格
# 语法
if [[ $n1 -gt $n2 && $n2 -lt $n3 ]]
then
conmmands
fi
#!/bin/bash
#
if
[[ $1 -gt $2 && $2 -lt $3 ]]
then
echo 'yes'
else
echo 'no'
fi
PS:macOS 中不能直接使用<>符号判断
# case 命令
- *)相当于 default
# 语法
case $var in
parttern1)
commands
parttern2)
commands
*)
ommands
esac
#!/bin/bash
#
case $1 in
ljc)
echo 'ljc'
;;
cw)
echo 'cw'
;;
*)
echo 'love'
;;
esac
# for 循环
# 简介
循环遍历一系列特定值,然后再结构体中针对每个特定值做处理
# 语法
list 可以是字符串、枚举、甚至是 ls 的返回值
遍历是通过系统分隔符 IFS(默认是空格)来分割值的,也就是说类似与 list='ljc cw xw chx'这种就相当于 js 中的[ljc,cw,xw,chx]
# 读取变量、列表的值
for $var in list
do
command
done
for i in ljc cw zc lzp
do
echo $i
done
for i in {1..20}
do
echo $i
done
list='ljc cw xw chx'
for i in $list
do
echo $i
done
IFS=":"
list='ljc cw xw chx'
# list='ljc:cw:xw:chx'
for i in $list
do
echo $i
done
# 系统分隔符改为: 则list会整个被当成一个字符串输出,将注释打开则和上一个例子相同
# 读取命令执行结果的值
使用命令替换$(command) 将命令输出的结果作为变量的值(输出)
软连接如果指向目录那么检测出来的也属于目录
FILE=$(ls)
for i in $FILE; do
if [ -d $i ]; then
echo "$i is dir"
elif [ -f $i ]; then
echo "$i is file"
fi
done
# 两者等价
for i in $(ls); do
if [ -d $i ]; then
echo "$i is dir"
elif [ -f $i ]; then
echo "$i is file"
fi
done
假如我们有一个文本
ljc love cw
zc
lzp
IFS=$'\n'
for i in $(cat ./case/for/text.txt); do
echo $i
done
得到结果
ljc love cw
zc
lzp
如果不更改IFS则输出
ljc
love
cw
zc
lzp
# c 语言风格的 for 命令
# 语法
for ((i = 1; i < 10; i++))
do
command
done
for ((i = 0; i <= 100; i++)); do
((sum += $i))
done
echo $sum
# 注意要用c语言的计算风格必须使用双() shell中变量定义只有顺序范围,所以在里面定义sum外面也可以拿到
# while 循环
- 条件语句的使用方法和 if 是一样的,可以使用[]也可以(())
# 语法
while command
do
commands
done
num=10
while ((num < 20 )); do
echo 'number is' $num
((num++))
done
while true; do
echo '死循环'
done
# until 命令
- 和 while 相反,知道满足某个条件的时候才会终止循环
until command
do
commands
done
num=10
until [ $num -eq 0 ]; do
echo 'stop ' $num
((num--))
done
# 控制循环的 break 指令
和 js 类似,但没有类似 let 的赋值作用域,所以多个 for 循环嵌套不能用相同的变量,必须使用 i,j,k 等
break + num 表示跳出几个循环,默认为 1
shell 日常使用中是不建议使用多个嵌套 for 循环的
for ((i = 0; i <= 5; i++)); do
echo '外' $i
for ((j = 10; j <= 20; j++)); do
echo '内' $j
if ((j > 15)); then
break 2
fi
done
done
echo $sum
# 控制循环的 continue 指令
表示不执行满足条件的循环轮次,并不是全部终止循环
continue + num 表示跳出几个循环层次,默认为 1,不经常用
for ((i = 0; i <= 20; i++)); do
if ((i > 10 && i < 15)); then
continue
else
echo "输出$i"
fi
done
# 处理循环的输出
- 使用重定向 > 将结果输出到一个文件中
for ((i = 0; i <= 20; i++)); do
echo "$i"
done > ./case/for/result.txt
- 可以通过管道对循环输出的结果做处理
for ((i = 0; i <= 20; i++)); do
echo "$i"
done | grep 5 # 查看包含5的结果