Shell

  1. 1. Shell解释器
  2. 2. Shell脚本入门
  3. 3. 变量
    1. 3.1. 系统变量
    2. 3.2. 自定义变量
      1. 3.2.1. 基本语法
      2. 3.2.2. 定义变量规则
    3. 3.3. 变量类型
    4. 3.4. 特殊变量
  4. 4. 运算符
  5. 5. 数组
    1. 5.1. 定义数组
    2. 5.2. 读取数组
    3. 5.3. 获取数组中的所有元素
    4. 5.4. 获取数组的长度
  6. 6. 条件判断
    1. 6.1. 常用的判断条件
  7. 7. 流程控制
    1. 7.1. if判断
    2. 7.2. case语句
    3. 7.3. for循环
    4. 7.4. while循环
  8. 8. read读取控制台输入
  9. 9. 函数
    1. 9.1. 系统函数
      1. 9.1.1. basename
      2. 9.1.2. dirname
    2. 9.2. 自定义函数
  10. 10. Shell工具
    1. 10.1. cut
    2. 10.2. sed
    3. 10.3. awk
    4. 10.4. sort

Shell是一个命令行解释器,它接受应用程序、用户命令,然后调用操作系统内核。Shell还是一个功能强大的编程语言,易编写,易调试,灵活性强

Shell解释器

查看Shell解释器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat /etc/shells

# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen
/bin/zsh
/usr/bin/zsh
  • bashsh的关系为:sh -> bash

Shell脚本入门

脚本以#!/bin/bash开头(指定解释器)

脚本执行方式:

  1. 采用bash或sh + 脚本的相对路径或绝对路径(不用赋予脚本+x权限)
  2. 采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x

第一种执行方法本质上bash解析器帮你执行脚本,所以脚本本身不需要执行权限,第二种执行方法,本质是脚本需要自己执行,所以需要执行权限

变量

系统变量

常用的系统变量:

  • $HOME
  • $PWD
  • $SHELL
  • $USER
1
2
3
echo $HOME

/home/zhangqiang
1
2
3
echo $PWD

/home/zhangqiang
1
2
3
echo $SHELL

/bin/zsh
1
2
3
echo $USER

zhangqiang

自定义变量

基本语法

  • 定义变量:变量=值
  • 撤销变量unset变量
  • 声明静态变量readonly变量,注意,不能用unset

注意:定义变量时等号左右不可以空格

定义变量规则

  1. 变量名称可以由字母,数字和下划线组成,但是不能以数字开头,环境变量名建议大写
  2. 等号两侧不能有空格
  3. 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
  4. 变量的值如果有空格,需要使用双引号或单引号括起来

变量类型

运行shell时,会同时存在三种变量:

  1. 局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量
  2. 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量
  3. shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

可把变量提升为全局环境变量,可供其他Shell程序使用(export 变量名

特殊变量

参数处理 说明
$n n为数字,$0代表该脚本名称,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含:${10}
$# 获取所有输入参数个数,常用于循环
$* 代表命令行中所有的参数,$*把所有参数看成一个整体
$@ 代表命令行中所有的参数,$@把每个参数区分对待
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$- 显示Shell使用的当前选项,与set命令功能相同
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误
1
2
3
4
5
6
7
#!/bin/bash

echo "$0 $1 $2 $3"

echo $#
echo $*
echo $@
1
2
3
4
5
6
bash test.sh hello world !

test.sh hello world !
3
hello world !
hello world !

$*与$@的区别:

  • 相同点:都是引用所有参数
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,则"$*“等价于 “1 2 3”(传递了一个参数),而”$@"等价于 “1” “2” “3”(传递了三个参数)

运算符

基本语法:

  • “$((运算式))” 或者 “$[运算式]”
  • expr
    • 加法:+
    • 减法:-
    • 乘法:\*
    • 除法:/
    • 取余:%
    • 赋值:=
    • 相等:==
    • 不相等:!=

注意乘法的表示,以及expr运算符之间要有空格

1
2
3
4
s=$[(2+3)*4]
echo $s

20

数组

数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小

与大部分编程语言类似,数组元素的下标由0开始

定义数组

Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:

1
array_name=(value1 value2 ... valuen)

我们也可以使用下标来定义数组:

1
2
3
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

读取数组

读取数组元素值的一般格式是:

1
${array_name[index]}
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

my_array=(A B "C" D)

echo "第一个元素为: ${my_array[0]}"
echo "第二个元素为: ${my_array[1]}"
echo "第三个元素为: ${my_array[2]}"
echo "第四个元素为: ${my_array[3]}"

获取数组中的所有元素

使用 @ 或 * 可以获取数组中的所有元素,例如:

1
2
3
4
5
6
7
8
9
#!/bin/bash

my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D

echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"

获取数组的长度

获取数组长度的方法与获取字符串长度的方法相同,例如:

1
2
3
4
5
6
7
8
9
#!/bin/bash

my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D

echo "数组元素个数为: ${#my_array[*]}"
echo "数组元素个数为: ${#my_array[@]}"

条件判断

基本语法:[ condition ]

注意:condition前后要有空格

  • 条件非空记为true
  • []返回false

常用的判断条件

  1. 两个整数之间比较
表示 说明
= 字符串比较
-lt 小于
-eq 等于
-gt 大于
-le 小于等于
-ne 不等于
-ge 大于等于
  1. 按照文件权限进行判断
表示 说明
-r 有读的权限(read)
-w 有写的权限(write)
-x 有执行的权限(execute)
  1. 安装文件类型进行判断
表示 说明
-f 文件存在并且是一个常规文件(file)
-e 文件存在(existence)
-d 文件存在并且是一个目录(directory)

流程控制

if判断

1
2
3
4
5
if [ condition1 ];then
code
elif [ condition2 ];then
code
fi

注意:[ 条件判断式 ],中括号与条件判断式之间必须要有空格;且if后也要有空格

case语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac

注意:

  • case行尾必须为in,每一个模式匹配必须以右括号)结束
  • 双分号;;表示命令序列结束,相当于java中的break
  • 最后的*)表示默认模式,相当于java中的default

case 后为取值,值可以为变量或常数。

值后为关键字 in,接下来是匹配的各种模式,每一模式最后必须以右括号结束,模式支持正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh

site="runoob"

case "$site" in
"runoob") echo "菜鸟教程"
;;
"google") echo "Google 搜索"
;;
"taobao") echo "淘宝网"
;;
esac

for循环

基本语法1

1
2
3
4
for(( 初始值;循环控制条件;变量变化 ))
do
code
done

例:从1加到100

1
2
3
4
5
6
7
8
#!/bin/sh

s=0
for((i=1;i<=100;i++))
do
s=$[$s+$i]
done
echo $s

基本语法2

1
2
3
4
for 变量 in 值1 值2 值3 ...
do
code
done

例:打印所有输入参数

1
2
3
4
for i in $*
do
echo $i
done

while循环

基本语法

1
2
3
4
while [ 条件判断式 ]
do
code
done

例:从1加到100

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

s=0
i=1
while [ $i -le 100 ]
do
s=$[$s+$i]
i=$[$i+1]
done

echo $s

也可以用Bash let命令写:它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量

1
2
3
4
5
6
7
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done

read读取控制台输入

1
read(选项)(参数)

选项:

选项参数 功能
-p 指定读取值时的提示符
-t 指定读取值时的等待的时间(秒)

参数:

  • 变量:指定读取值的变量名

例:提示7秒内,读取控制台输入的名称

1
2
read -t 7 -p "Enter your name in 7 seconds " NAME
echo $NAME

函数

系统函数

basename

1
basename [string/pathname][suffix]

basename命令会删掉所有的前缀包括最后一个/字符,然后将字符串显示出来

suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉

1
2
3
basename /home/zhangqiang/test.txt

test.txt
1
2
3
basename /home/zhangqiang/test.txt .txt

test

dirname

dirname文件绝对路径:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)

1
2
3
dirname /home/zhangqiang/test.txt

/home/zhangqiang

自定义函数

1
2
3
4
5
6
7
[ function ] funname [()]

{
action;

[return int;]
}
  • 必须在调用函数的地方之前,先声明函数,shell脚本是逐行运行。不会像其他语言一样先编译
  • 函数返回值:只能通过 $? 系统变量获得,可以显示加:return 返回,如果不加,将以最后一条命令运行结果作为返回值。return 后跟数值 n(0255)n(0 - 255)
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum$anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

Shell工具

cut

cut工作就是"剪",具体的说就是在文件中负责剪切数据用的。cut命令从文件的每一行剪切字节,字符和字段并将这些字节,字符和字段输出

1
cut [ option ] filename

选项:

选项参数 功能
-f 列号,提取第几列
-d 分隔符,按照指定分隔符分割列
1
2
3
4
5
# 切割test.txt第一列
cut -d " " -f 1 test.txt

# 切割test.txt第二,三列
cut -d " " -f 2,3 test.txt
1
2
3
4
5
6
7
8
# 选取系统PATH变量值,第二个冒号开始后的所有路径
echo $PATH

/home/zhangqiang/.pyenv/shims:/home/zhangqiang/.pyenv/bin:/home/zhangqiang/.nvm/versions/node/v12.18.4/bin:/home/zhangqiang/.zplug/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/ProgramData/chocolatey/bin:/mnt/c/Program Files/Git/cmd:/mnt/c/Program Files/Microsoft VS Code/bin:/mnt/c/Program Files/dotnet/:/mnt/c/Users/zhangqiang/AppData/Roaming/nvm:/mnt/c/Program Files/nodejs:/mnt/c/Program Files/Docker/Docker/resources/bin:/mnt/c/ProgramData/DockerDesktop/version-bin:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA NvDLISR:/mnt/c/Users/zhangqiang/.pyenv/pyenv-win/bin:/mnt/c/Users/zhangqiang/.pyenv/pyenv-win/shims:/mnt/c/Users/zhangqiang/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/zhangqiang/AppData/Roaming/nvm/v12.18.4:/home/zhangqiang/library/go/bin:/home/zhangqiang/go/bin

echo $PATH | cut -d : -f 3-

/home/zhangqiang/.nvm/versions/node/v12.18.4/bin:/home/zhangqiang/.zplug/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/ProgramData/chocolatey/bin:/mnt/c/Program Files/Git/cmd:/mnt/c/Program Files/Microsoft VS Code/bin:/mnt/c/Program Files/dotnet/:/mnt/c/Users/zhangqiang/AppData/Roaming/nvm:/mnt/c/Program Files/nodejs:/mnt/c/Program Files/Docker/Docker/resources/bin:/mnt/c/ProgramData/DockerDesktop/version-bin:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA NvDLISR:/mnt/c/Users/zhangqiang/.pyenv/pyenv-win/bin:/mnt/c/Users/zhangqiang/.pyenv/pyenv-win/shims:/mnt/c/Users/zhangqiang/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/zhangqiang/AppData/Roaming/nvm/v12.18.4:/home/zhangqiang/library/go/bin:/home/zhangqiang/go/bin

cut指令不会改变原文件

sed

sed是一种流编辑器,它一次处理一行内容

处理时,把当前处理的行储存在临时缓冲区中,称为模式空间,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾

文件内容并没有改变,除非你使用重定向储存输出

1
sed [ option ] 'command' filename

选项参数说明:

选项参数 功能
-e 直接在指令列模式上进行sed的动作编辑

常用命令功能描述:

命令 功能描述
a 新增,a后面可以接字符串,在下一行出现
d 删除
s 查找并替换
1
2
3
4
5
6
7
8
cat test.txt

dong shen
guan zhen
wo wo
lai lai

le le
1
2
3
4
5
6
7
8
9
10
# 将 "mei nv" 这个单词插入到test.txt的第二行下,并打印
sed "2a mei nv" test.txt

dong shen
guan zhen
mei nv
wo wo
lai lai

le le
1
2
3
4
5
6
7
8
# 删除 test.txt 文件所有包含 "wo" 的行
sed "/wo/d" test.txt

dong shen
guan zhen
lai lai

le le
1
2
3
4
5
6
7
8
9
# 将 test.txt 文件中 "wo" 替换为 "ni"
sed "s/wo/ni/" test.txt

dong shen
guan zhen
ni wo
lai lai

le le

注意:加上g后表示global:sed “s/wo/ni/g” test.txt 意为全部替换

1
2
3
4
5
6
7
8
# 将 test.txt 文件中的第二行删除并将 "wo" 全部替换为 "ni"
sed -e "2d" -e "s/wo/ni/g" test.txt

dong shen
ni ni
lai lai

le le

-e用于多个执行语句当中

awk

awk是一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理

1
awk [ option ] 'pattern1 {action1} pattern2 {action2} ...' filename 
  • pattern:表示awk在数据中查找的内容,就是匹配模式
  • action:在找匹配内容时所执行的一系列命令

选项参数说明:

选项参数 功能
-F 指定输入文件拆分隔符
-v 赋值一个用户定义变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 数据准备
cp /etc/passwd ./
cat passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
zhangqiang:x:1000:1000:,,,:/home/zhangqiang:/bin/zsh
1
2
3
4
# 搜索passwd文件以root关键字开头的所有行,并输出改行的第1列和第7列,中间以逗号分隔
awk -F : '/^root/ { print $1 "," $7 }' passwd

root,/bin/bash

注意:只有匹配了pattern的行才会执行action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 只显示/etc/passwd的第一列和第七列,以逗号分隔,且在所有行前面添加列名 "user,shell",并在最后一行添加 "hello"
awk -F : 'BEGIN { print "user,shell" } { print $1 "," $7 } END { print "hello" }' passwd

user,shell
root,/bin/bash
daemon,/usr/sbin/nologin
bin,/usr/sbin/nologin
sys,/usr/sbin/nologin
sync,/bin/sync
games,/usr/sbin/nologin
man,/usr/sbin/nologin
lp,/usr/sbin/nologin
mail,/usr/sbin/nologin
news,/usr/sbin/nologin
uucp,/usr/sbin/nologin
proxy,/usr/sbin/nologin
www-data,/usr/sbin/nologin
backup,/usr/sbin/nologin
list,/usr/sbin/nologin
irc,/usr/sbin/nologin
gnats,/usr/sbin/nologin
nobody,/usr/sbin/nologin
systemd-network,/usr/sbin/nologin
systemd-resolve,/usr/sbin/nologin
systemd-timesync,/usr/sbin/nologin
messagebus,/usr/sbin/nologin
syslog,/usr/sbin/nologin
_apt,/usr/sbin/nologin
tss,/bin/false
uuidd,/usr/sbin/nologin
tcpdump,/usr/sbin/nologin
sshd,/usr/sbin/nologin
landscape,/usr/sbin/nologin
pollinate,/bin/false
zhangqiang,/bin/zsh
hello

注意:BEGIN在所有数据读取行之前执行;END在所有数据执行后执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 将passwd文件中的用户id增加数值1并输出
awk -F : -v i=1 '{ print $3+i }' passwd

1
2
3
4
5
6
7
8
9
10
11
14
34
35
39
40
42
65535
101
102
103
104
105
106
107
108
109
110
111
112
1001

awk的内置变量:

变量 说明
FILENAME 文件名
NR 已读的记录数
NF 浏览记录的域的个数(切割后列的个数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 统计passwd文件名,每行的行号,每行的列数
awk -F : '{ print "filename:" FILENAME ", line number:" NR ", columns:" NF}' passwd

filename:passwd, line number:1, columns:7
filename:passwd, line number:2, columns:7
filename:passwd, line number:3, columns:7
filename:passwd, line number:4, columns:7
filename:passwd, line number:5, columns:7
filename:passwd, line number:6, columns:7
filename:passwd, line number:7, columns:7
filename:passwd, line number:8, columns:7
filename:passwd, line number:9, columns:7
filename:passwd, line number:10, columns:7
filename:passwd, line number:11, columns:7
filename:passwd, line number:12, columns:7
filename:passwd, line number:13, columns:7
filename:passwd, line number:14, columns:7
filename:passwd, line number:15, columns:7
filename:passwd, line number:16, columns:7
filename:passwd, line number:17, columns:7
filename:passwd, line number:18, columns:7
filename:passwd, line number:19, columns:7
filename:passwd, line number:20, columns:7
filename:passwd, line number:21, columns:7
filename:passwd, line number:22, columns:7
filename:passwd, line number:23, columns:7
filename:passwd, line number:24, columns:7
filename:passwd, line number:25, columns:7
filename:passwd, line number:26, columns:7
filename:passwd, line number:27, columns:7
filename:passwd, line number:28, columns:7
filename:passwd, line number:29, columns:7
filename:passwd, line number:30, columns:7
filename:passwd, line number:31, columns:7

sort

sort命令在linux中非常有用,他将文件进行排序,并将排序结果标准输出

1
sort (option) (参数)
选项 说明
-n 依照数值大小排序
-r 以相反的顺序来排序
-t 设置排序时所用的分隔字符
-k 指定需要排序的列
1
2
3
4
5
6
7
cat test.txt

bb:40:5.4
bd:20:4.2
xz:50:2.3
cls:10:3.5
ss:30:1.6
1
2
3
4
5
6
7
8
# 按照 ":" 分割后的第二列倒序排序
sort -t : -nrk 2 test.txt

xz:50:2.3
bb:40:5.4
ss:30:1.6
bd:20:4.2
cls:10:3.5