Shell
shell 基础和语法
变量
#!/bin/bash
# 变量名=变量值
page_size=1
page_num=2
# 将命令赋值给变量
_ls=ls
# 将命令结果赋值给变量
file_list=$(ls -a)
# 默认字符串 不会进行+运算
total=page_size*page_num
# 声明变量为整型
let total=page_size*page_num
declare -i total=page_size*page_num
# 导出环境变量
export total
declare -x total2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
系统环境变量

管道
管道与管道符|,作用是将前一个命令的结果传递给后面的命令 cmd1 | cmd2 管道右侧的命令必须能接受标准输入才行,比如grep命令,ls、mv等不能直接使用,可以使用xargs预处理 管道命令仅仅处理stdout,对于stderr会予以忽略, 可以使用set-o pipefail设置shell遇到管道错误退出
cat palterform.access.log | grep ERROR
netstat -an | grep ESTABLISHED | wc -l
find . -maxdepth 1 -name "*.sh" | xargs ls -l2
3
4
5
重定向
输出重定向符号
>:覆盖写入文件
>>:追加写入文件
2>:错误输出写入文件
&>:正确和错误输出统一写入到文件中
输入重定向符号
<
<<
ls -l >> list.txt 2>&1
cat list.txt
while read -r line; do echo $line | cut -d " " -f 1 | xargs >> auth.txt; done < ./list.txt
cat auth.txt
wc -l <<EOF2
3
4
5
6
7
8
判断命令
shell中提供了
test、[、[[三种判断符号,可用于:整数测试、字符串测试、文件测试
test condition
[ condition ]
[[ condition ]]2
3
注意:
- 中括号前后要有空格符
- [和test是命令,只能使用自己支持的标志位,
<、>、=只能用来比较字符串 - 中括号内的变量,最好都是用引号括起来
- [[更丰富,在整型比较中支持
<、>、=,在字符串比较中支持=~正则
1、常用判断条件
(1) 两个整数之间比较
= 字符串比较
-lt 小于(less than)
-le 小于等于(less equal)
-eq 等于(equal)
-ne 不等于(Not equal)
-gt 大于(greater than)
-ge 大于等于(greater equal)
(2) 按顺文件权限进行判断
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
(3) 按顺文件关型进行判断
-f 文件存在并且是一个常规的文件(file)
-e 文件存在(existence)
-d 文件存在并是一个目录(directory)
2 、练习实操 (1) 逻辑语句 && 和 || && 前面条件成立,后面语句才会执行(逻辑与) || 前面条件不成立,后面语句才会执行(逻辑或)
cat demo.sh
#!/bin/bash
# && 逻辑与 和 逻辑或
echo $#
[ $# -gt 2 ] && echo "参数的个数大于2"
[ $# -lt 2 ] || echo "参数的个数大于2----"
sh demo.sh 1 2 3
3
参数的个数大于2
参数的个数大于2----
sh demo.sh 1 2
2
参数的个数大于2----
sh demo.sh 1
12
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(2) 利用命令的执行结果进行判断 判断用户是否存在,创建用户
参考:echo $? 输出的0 和 1 ,表示Y 与 F
#!/bin/bash
#如果用户zhangsan不存在,则添加用户zhangsan
id zhangsan &> /dev/null && echo "zhangsan用户存在,不用添加"
id zhangsan &> /dev/null || useradd zhangsan2
3
4
流程控制
1、if 判断 基本格式
注意事项: (1) [ 条件判断式 ],中括号和条件判断式之间必须有空格 (2) if后要有空格
if [ 条件判断句 ];then
程序
fi
#或者
if [ 条件判断句 ]
then
程序
fi2
3
4
5
6
7
8
9
10
案例:判断年龄
[root@clb1 shell]# cat if.sh
#!/bin/bash
if [ $1 -lt 18 ];then
echo "未成年"
elif [ $1 -ge 18 -a $1 -le 30 ];then
echo "青年"
else
echo "中老年"
fi
[root@clb1 shell]# sh if.sh 22
青年
[root@clb1 shell]# sh if.sh 33
中老年
[root@clb1 shell]# sh if.sh 3
未成年2
3
4
5
6
7
8
9
10
11
12
13
14
15
2、case语句
注意事项
case行尾必须为单词“in",每一个模式匹配必须以右括号 )结束
双分号 ;; 表示命令序列结束,相当于java中的break。
最后的*)表示默认模式,相当于java中的default。
case $变量名 in
“值1”)
如果变呈的值等于值1,则执行程序1
;;
“值2”)
如果变星的值等于值2,则执行程序2
;;
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac2
3
4
5
6
7
8
9
10
11
案例:判断输入
[root@clb1 shell]# cat case.sh
#!/bin/bash
case $1 in
"start")
echo "你输入的是start"
;;
"stop")
echo "你输入的是stop"
;;
*)
echo "你输入的是其他"
;;
esac
[root@clb1 shell]# sh case.sh stop
你输入的是stop
[root@clb1 shell]# sh case.sh start
你输入的是start
[root@clb1 shell]# sh case.sh st
你输入的是其他2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3、循环
- while循环 while condition;do 程序段;done
- until循环 until condition;do 程序段;done
- for循环 for var in [words..];do 程序段;done
函数
printName(){
if [ $# -1t 2 ]; then
echo "illegal parameter."
exit 1
fi
echo "firstname is: $1"
echo "lastname is: $2"
}
printName jacky chen2
3
4
5
6
7
8
9
10
注意
- shell自上而下执行,函数必须在使用前定义
- 函数获取变量和shell script类似,$0代表函数名,后续参数通过$1、$2..获取
- 函数内return仅仅表示函数执行状态,不代表函数执行结果
- 返回结果一般使用echo、printf,在外面使用$0、``获取结果
- 如果没有return,函数状态是上一条命令的执行状态,存储在$?中
模块化
模块化的原理是在当前shell内执行函数文件,方式: source[函数库的路径]
# math.sh
#!/bin/bash
# add函数
# @return platForm
function add(){
declare -i res=$1+$2
echo $res
}
#!/bin/bash
source './math.sh'
total=$(add 1 2)
echo $total2
3
4
5
6
7
8
9
10
11
12
13
常见命令

执行
1、shell脚本一般以.sh结尾,也可以没有,这是一个约定;第一行需要指定用什么命令解释器来执行
#! /bin/bash
#! /usr/bin/env bash2
2、启动方式
#文件名运行
./filename.sh
#解释器运行
bash./filename.sh
#source运行
source ./filename.sh2
3
4
5
6
7
8
shell展开
- 大括号展开(Brace Expansion)
{..} - 波浪号展开(Tilde Expansion)
~ - 参数展开(Shell Parameter Expansion)
- 命令替换(Command Substitution)
- 数学计算(Arithmetic Expansion)
$((..)) - 文件名展开(Filename Expansion)
* ? [..]外壳文件名模式匹配
大括号展开
一般由三部分构成,前缀、一对大括号、后缀,大括号内可以是逗号分割的字符串序列,也可以是序列表达式
{x.y[..incr]}
# 字符串序列
a{b,c,d}e=abe ace ade
# 表达式序列,(数字可以使用incr调整增量,字母不行)
{1..5} => 12345
{1..5..2} => 1 3 5
{a..e} => a b c d e2
3
4
5
6
7
8
9
波浪号展开
# 当前用户主目录
~ => $HOME
~/f00 => $HOME/foo
# 指定用户的主目录
~fred/foo => 用户fred的$HOME/foo
# 当前工作目录
~+/foo => $PWD/foo
# 上一个工作目录
~-/foo => ${$OLDPWD-'~-'}/foo2
3
4
5
6
7
8
9
10
11
12
13
参数展开
间接参数扩展
${!parameter},其中引用的参数并不是parameter而是parameter的实际的值参数长度
${#parameter}空参数处理
${parameter:-word} #为空替换$parameter:=word} #为空替换,并将值赋给$parameter变量${parameter:?word} #为空报错${parameter:+word} #不为空替换参数切片
$(parameter:offset)$(parameter:offset:length)参数部分删除
${parameter%word}#最小限度从后面截取word${parameter%%word}#最大限度从后面截取word${parameteri#word}#最小限度从前面截取word${parameter##word}#最大限度从前面截取word
#/bin/sh
str=abcdefg
spl=s{str##*d)
sp2=${str%%d*}
echo $sp1 # 输出efg
echo $sp2 # 输出abc2
3
4
5
6
7
命令替换
在子进程中执行命令,并用得到的结果替换包裹的内容,形式上有两种:
$()或`…`
#!/bin/bash
echo $(whoimi)
foo(){
echo "asdasd"
}
a=foo2
3
4
5
6
数学计算 $((..))
#!/bin/bash
echo $((1+3))2
3
文件名展开 当有单词没有被引号包裹,且其中出现了*,?,and[字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变。
#!/bin/bash
echo D*
#输出当前目录下所有以D字母开头的目录、文件2
3
4
调试和前端集成
调试
- 普通log,使用echo、printf
- 使用set命令
- vscode debug插件
#/bin/sh
set -uxe -o pipefail
echo "hello world"2
3
4
| set配置 | 作用 | 补充 |
|---|---|---|
| -u | 遇到不存在的变量就会报错,并停止执行 | -o nounset |
| -x | 运行结果之前,先输出执行的那一行命令 | -o xtrace |
| -e | 只要发生错误,就终止执行 | -o errexit |
| -o pipefail | 管道符链接的,只要一个子命令失败,整个管道命令就失败,脚本就会终止执 | |
| 行. |
vscode 插件
1.shellman: 代码提示和自动补全
2.shellcheck: 代码语法校验
3.shell-format: 代码格式化
4.Bash Debug: 支持单步调试
- 安装vscode插件
- 编写launch.json文件
- 升级bash到4.x以上版本
# 1,安装最新版本bash
brew install bash
# 2.查看安装路径
which -a bash
# 3.将新版本bash路径加入PATH
PATH="/usr/local/bin/bash:SPATH"
# 4.配置vscode launch.json启动文件
{
"version": "0.2.0",
"configurations": [
{
"type": "bash",
"request": "launch",
"name": "Bash debugger",
"args": [],
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/demo.sh",
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
前端集成
- node中通过exec、spawn调用shell命令
- shell脚本中调用node命令
- 借助zx等库进行javascript、shell script的融合
- 借助shell完成系统操作,文件io、内存、磁盘系统状态查询等
- 借助nodejs完成应用层能力,网络io、计算等
