Shell
Shell本身也是一门编程语言,学了不用会忘。
会写简单脚本、会读脚本即可。
0. 关键字汇总
sleep 1s sleep 1m sleep 1h sleep 1d
#命令执行结果赋值给变量 a=`ls -al`
#整数运算赋值给变量 a=`expr 2 \* 3` #将命令expr 2 \* 3的结果赋值给a a=$(( 2*3 ))
#变量自增、自减 let i++ i=`expr i + 1` i=$(( i+1 ))
if [ $? -eq 0 ] then fi if (( i<10 ))
i=0 while (( i<10 )) do echo $i let i++ i=`expr $i + 1` while : #死循环
for i in ${arr[*]} do echo $i done for (( i=0;i<10;i++ )) for (( i=0;i<${#arr[*]};i++))
1. 概念
-
不再是bash中输入一个一个单独的命令返回一个一个单独的结果,而是将命令和代码写在.sh脚本文件中,运行文件可执行一系列操作。类似于Windows的.bat批处理。
-
脚本文件需要脚本解释器,Linux中脚本解释器有很多种,如:/bin/sh和/bin/bash。Linux默认bash,一般使用bash。
-
Python脚本可以/bin/Python解释器执行。
-
脚本第一行以下列代码指定解释器
#!/bin/bash -
执行脚本前,先添加执行权限
chmod ug+x *.sh # u表示用户,g表示同组用户,+表示增加权限,x表示执行 -
注释
#注释单行
2. 父子shell
-
在shell中输入bash会打开一个子shell,exit可退出子shell
-
/bin/bash执行脚本文件时会开启一个bash子进程,执行完脚本即从bash子进程退出。子bash的变量不会影响父bash的变量。
- 不开启bash子进程的执行方法:在当前shell以
source xx.sh
的方式引入。这样将脚本中变量至今引入当前shell,当前shell的变量将会受到影响
- 子shell变量的作用域不到父shell
3. 变量
(1)类型
-
环境变量(也叫全局变量)——能够被当前shell及其子shell都访问的变量。
-
大部分的系统预置变量,如:
$HOME——当前用户主目录
$PWD——当前目录
$SHELL——当前使用的shell解释器
$USER——当前用户
-
set命令:输出所有变量(包括环境变量、局部变量)
-
env命令:只输出环境变量
-
-
局部变量——只能被当前shell访问,无法被父shell或子shell访问的变量。
-
特殊变量——$?
用于获取上一个命令执行的“结果码”。并不能返回执行结果本身,只能返回0-255。0表示执行无错,1-255表示错误码。
如:
ls -la echo $? # 0
(2)变量的定义与使用
-
shell变量类型默认是字符串
-
定义/赋值
name="ssss" -
=两侧不能有空格。因为Linux命令的格式是
命令+空格+参数+空格+操作对象
,一旦在=两侧加了空格,系统将会误以为变量名是命令,而以解析命令的方式处理。 -
"ssss"的引号可以省略
-
双引号识别特殊字符。单引号不识别特殊字符,会直接将引号中的内容直接作为字符串。
age=20 age1="${age}" age2='${age}' echo age1 # 20 echo age2 # ${age}
-
-
使用变量
echo ${name} # 或省略{},加上{}是为了避免变量名歧义更加规范 -
删除变量
变量删除后不再能够使用
unset name -
只读变量
name="sss" readonly name # 定义为只读变量后不能再试图通过赋值来修改变量值
(3)字符串
shell中变量取值默认的是字符串。
-
单引号不识别特殊字符,引号里什么值就是什么值。
-
字符串拼接
写在一起就行
a="hello" b=" world" c=$a$b echo $c # hello world -
双引号识别特殊字符
age="20" age2='${age}' age3="${age}" echo $age2 #'${age}' #单引号不识别,直接把引号中内容打印出来 echo $age3 #20 #双引号则会将${age}识别成20 -
获取字符串长度
${#"helloworld"}
(4)数组
-
定义
arr=(val1 val2 val3 val4) 或 arr=() arr[0]=val1 arr[1]=val2 arr[2]=val3 arr[3]=val4 -
访问元素
echo ${arr[0]} #获取第一个元素 echo ${arr[-1]} #获取最后一个元素 -
获取数组长度
len=${#arr[*]} -
获取数组所有元素
${arr[*]} -
获取所有下标
${!array[*]} -
遍历数组
for i in "${array[*]}" #这里i是array的每个元素 do echo $i done 或 for i in ${!array[*]} #这里i是array的下标 do echo ${array[i]} done -
关联数组-以字符串作为下标key
declare -A arr arr[name]="wk" arr[age]=30 或 declare -A arr=([name]="wk" [age]=30)
4. 命令替换
将命令执行的结果对变量进行赋值
使用$()
或``将要执行的命令括起来
a=$(ls ./) echo $a b=`ls ./` echo $b
5. 读取和输出
read
read -p "提示信息" 变量名
echo
echo "hello world"
6. 流程控制
(1)条件表达式
test expression
可简写成[ expression ]
。注意expression和两侧括号间有空格。if和括号之间也有空格
if [ -d "/home/wk/workspace" ] then echo "dir exist.." fi
-
条件运算符
文件判断
-e filename:判断文件是否存在
-d filename:判断文件是否存在,且是否是目录文件
-x filename:判断文件是否存在,且是否具有可执行权限
-r filename:判断文件是否存在,且是否具有可读权限
-w filename:判断文件是否存在,且是否具有可写权限
整数比较,在bash风格中必须使用这种。但是在(())中就可以不用
-eq 等于
-ne 不等
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
字符串比较
str1==str1 字符串相等
str1!=str2 字符串不等
if [ i eq 10 ] do echo $i done if (( i==10 )) do echo $i done
(2)if语句
if cond1 then command1 elif cond2 then command2 else command3 fi
(3)for循环和while循环
-
while的bash风格
while [ condition ] do ... done #死循环写法 i=1 while : do let i++ #等价于i=$($i + 1)或i=`expr $i + 1` done -
for的bash风格
for var in list do commands done #var在循环语句外也能使用,且保持最后一个var的值 -
list可以是命令执行的结果
filename="/home/wk/workspace/demo.cpp" for var in $(cat $filename) list=$(cat $filename) for var in list -
C风格
for (( i=0;i<10;i++ )) do ... done while (( i<10 )) do ... done (4)for和if嵌套
7. 函数传参
函数名后跟参数值。函数体内以$1/$2/$3...表示参数:
- $0——文件名
- $1/$2/$3——参数
- $#——传递给脚本的参数个数
- $*——将所有参数以一个字符串的形式输出
- $#——将所有参数各个以字符串的形式输出s
- $$ 这个脚本/程序的PID(脚本运行的当前进程PID)
- $? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
8. 整数数值计算
将整数计算的数值赋值给变量:
-
方法1
使用(()),在括号内部可以直接进行整数计算。
a=$((1+3)) b=$((3*3)) c=$(($a+$b))
- 方法2
expr是一个命令,表示将后面的作为一个整数表达式进行计算。反引号赋值的方式,将expr命令的结果,也就是表达式的计算结果赋值给a。
a=`expr 3 \* 3` #这种方法写的时候表达式数字和运算符间要有空格,乘法要转义字符,否则会被识别为通配符
9. 函数
-
定义
shell是脚本语言,是一行一行执行,不会像编译型语言那样进行编译,所以在调用函数前必须要先定义。
func(){ commands... return或echo } -
调用
通过函数名func调用
-
只能通过$?获取最近的执行的函数的返回值,0表示无错。
-
返回值:可以显式的以return返回,return后跟0-255之间的数值(并不是能够返回任意结果,只能返回一个“结果码”),可用0表示执行无错,1,2,3等具体数字表示错误信息。
10. 重定向
> #输出重定向 >> #输出追加
11. sleep命令
shell中休眠时间
sleep 1s #1秒 sleep 1m #1分 sleep 1h #1小时 sleep 1d #1天
12. timeout-超时终止
用于限定命令或脚本的执行时间,超过设定时间若命令仍在执行则kill进程。
具体使用见man timeout
timeout 时间 命令/脚本
- timeout后接函数的话无效
timeout 10s ping www.baidu.com #ping命令执行10s #开辟两个进程,父进程timeout 10s ping www.baidu.com,子进程ping www.baidu.com
timeout 1m ./test.sh
14. 计算shell脚本执行时间
shell脚本运行时间,下次用到可直接copy starttime=`date +'%Y-%m-%d %H:%M:%S'` 需执行的程序 endtime=`date +'%Y-%m-%d %H:%M:%S'` start_seconds=$(date --date="$starttime" +%s); end_seconds=$(date --date="$endtime" +%s); echo "本次运行时间: "$((end_seconds-start_seconds))"s"
计算脚本执行时间: #!/bin/bash UseTime () { startTime=`date +%Y%m%d-%H:%M` startTime_s=`date +%s` $Command #根据自己脚本路径,测试脚本文件执行时间(sh test.sh) endTime=`date +%Y%m%d-%H:%M` endTime_s=`date +%s` sumTime=$[ $endTime_s - $startTime_s ] useTime=$[ $sumTime / 60 ] echo "$startTime ---> $endTime" "Totl:$useTime minutes" >> /tmp/usertime.txt } hello () { echo "hello !" sleep 120 } Command=hello UseTime $Command 计算脚本使用时间分钟 cat /tmp/usertime.txt 20170510-14:54 ---> 20170510-14:56 Totl:2 minutes
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)