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的变量。

image

  • 不开启bash子进程的执行方法:在当前shell以source xx.sh的方式引入。这样将脚本中变量至今引入当前shell,当前shell的变量将会受到影响
    image
  • 子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等具体数字表示错误信息。
    image

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
posted @   徘徊彼岸花  阅读(27)  评论(0编辑  收藏  举报
编辑推荐:
· 基于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)
点击右上角即可分享
微信分享提示