计算机工具基础(三)——Shell语法基础

Shell语法基础

MIT《Missing in CS Class(2020)》:Class 2笔记

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

脚本文件

  • 脚本语言为解释执行,其运行需有解释器,如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\) 项参数。类似于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),将commandstdout写入临时文件中,可作为其他命令的文件读入。例:

      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 @ 2025-01-29 04:00  椰萝Yerosius  阅读(49)  评论(0)    收藏  举报  来源