Class2(2020):Shell基础(二)——Shell脚本设计基础

本系列博客为MIT的《Missing in CS Class》的课程笔记。

Class2(2020):Shell基础(二)——Shell脚本设计基础

注:若无特殊说明,本文中带有[]的部分均为可选参数

脚本文件

  • 脚本语言为解释执行,其运行需有解释器,如Python。
  • Shell是一种脚本语言,其文件扩展名为.sh
  • 脚本文件的首行一般为#! <shell_name>,符号#!被称为shebang,其规定该脚本以何种Shell解释器执行。一般采用env(/usr/bin/env)程序,到$PATH中查找某种解释器在何位置,如#!/usr/bin/env shell
  • 若同一行有多条命令,用;分隔
  • 执行脚本:分为子Shell执行与当前Shell执行。若为子Shell执行,在不使用export的情形下,脚本中定义的各种变量、函数、环境都不会被带回当前Shell;若为当前Shell执行则反之,可在后续命令中调用脚本中定义的变量、函数等内容。
    • ./<script_name>.sh:仅当该脚本有可执行权限(x)时,根据shebang中规定的解释器,创建一个独立子Shell以执行该脚本
    • <shell_name> ./<script_name>.sh:无论该脚本是否有可执行权限,忽略shebang,以<shell_name>创建一个独立子Shell以执行该脚本
    • source ./<script_name>.sh. ./<script_name>.sh:无论该脚本是否有可执行权限,忽略shebang,直接在当前Shell中执行该脚本,相当于将脚本中进行的修改注入到当前Shell。

变量

  • 变量赋值:Shell与其他多数脚本语言一致,变量无需定义,直接赋值即可。右值可为数字、字符串、其他变量、数组、命令替换等。<name>=<value>
    注意赋值中各符号间不能有任何空格。

  • 变量可被重新赋值使用。

  • 变量使用:$<name>

  • 删除变量:unset <name>

  • 输出:

    • echo:如echo $a

    • 格式化输出:printf <format_string> [arg_list],与C中相同

  • Shell定义了一些保留变量

    • $0:脚本名
    • $1-$9:脚本执行的第 i i i 项参数。类似于C中main函数的形参argv[]
    • $@:所有参数
    • $#:参数数量。类似于C中main函数的形参argc
    • $$:当前脚本的PID(进程识别码)
    • $?:上条程序的返回值。
    • !!:上条包含所有参数的完整命令。如执行命令后被返回Permission Denied,使用sudo !!即可重新提升执行
    • $_:上条命令的最后一项参数。如:mkdir 1cd $_

数组、字符串

  • Shell只支持一维数组,所有value都会被视为字符串处理

    • 初始化:<array_name>=(<value1>,<value2>,...)

    • 赋值:<array_name>[<index>]=<value>

    • 随机访问:${<name>[<index>]}。特别的,<idx>@时,代表取数组中所有元素。

  • 关系数组:相当于Python中的dic(字典)、C++中的map。与普通数组不同,关系数组必须声明后才能使用。

    • 声明:declare -A <array_name>

    • 初始化:declare -A <array_name>=(["<key1>"]="<value1>" ["<key2>"]="<value2>" ...),其中<key>必须唯一。

    • 赋值:<array_name>["<key>"]="<value>"

  • 字符串:

    • 单引号包围的字符串:被视为字符串字面常量,所有内容将被原样存储,变量也不会被替换。如echo '$a':输出$a
    • 双引号包围的字符串:正常替换变量。如echo "$a":输出:b
    • 字符串长度:${#<name>}

命令替换、进程替换

  • 命令替换:$(<command>)<command>命令的stdout替换$(<command>)本身。如:

    today=$(date) #将输出赋值给变量
    echo "$today"
    
    for i in $(ls) ; do #遍历文件
    	echo "$i"
    done
    
    cd $(ls)
    
  • 进程替换:

    • 输出重定向:<(<command>),将<command>stdout写入临时文件中,可作为其他命令的文件读入。例:

      diff <(ls <dir1>) <(ls <dir2>)
      
    • 输入重定向:>(<command>),将其他命令的stdout写入临时文件中,由<command>读取。效果等价于管道符|

流程控制

选择结构

if…fi

注意Shell中的分支不可为空,若不需要就不要写对应的分支。注意在每个<condition>后都需加then

  • 单分支结构:if then ... fi

    if <condition> ; then
    	<command>
    fi
    
  • 双分支结构:if then ... else ... fi

    if <condition> ; then
    	<command>
    else
    	<command>
    fi
    
  • 多分支结构:if then ... elif then ... else ... fi

    if <condition> ; then
    	<command>
    elif <condition> ; then
    	<command>
    else
    	<command>
    fi
    

<condition>为布尔表达式时的两种表示形式:

  • [<bool_expression>]-eq:判断两个数字是否相等;-ne:判断两个数字是否不相等;-lt:判断数字是否小于;-le:判断数字是否小于等于;-gt:判断数字是否大于;-ge:判断数字是否大于等于。
  • ((<bool_expression>)):算术专用的布尔表达式,直接使用关系运算符即可。
case...esac
case <variable> in
    <pattern>)
    	<command>
        ;;
    [
    *) #相当于default
    	<command>
        ;;
    ]
esac

类似于C中的switch,顺次进行匹配。case...esac并没有原生的default,因此在结尾使用通配符*对未匹配内容进行匹配。

<pattern>中若有多个匹配规则,用|(或)连接,如1|2|3。可使用通配符、字符集([])。

循环结构

for
for <variable> in <object> ; do
	<command>
done
  • 传入列表:

    for i in 1 2 3 4 5 ; do
    	echo "$i"
    done
    
  • 传入范围序列$(seq)(相当于Python的range(),注意Shell的seq的左闭右闭区间):

    for <variable> in $(seq <start> <end> [<foot>]) ; do
    	<command>
    done
    
  • 传入花括号{<start>..<end>}:等价于$(seq <start> <end>)$

    for <variable> in {<start>..<end>} ; do
    	<command>
    done
    
while
while <condition> ; do
    <command>
done

<condition>为真时,循环执行循环体

until
until <condition> ; do
    <command>
done

<condition>为假时,循环执行循环体,直到<condition>为真

跳转语句

  • continue:跳出循环的当前轮
  • break:跳出整个循环

函数

  • 函数定义
function_name() {
    <command>
    [return ...]
}

function function_name {
    <command>
    [return ...]
}
  • 函数调用
function_name [argv,...]
posted @   椰萝Yerosius  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示