Shell编程基础

变量

定义、使用、删除

  • 定义变量

    • 定义时不加$符号
    • 变量名和等号之间不能有空格
    • 变量名只能由英文字母、数字、下划线,且不以数字开头, 不能用bash中的关键字
    • 已经定义变量可以重新定义
  • 使用变量

    • 即可使用, 未定义变量直接使用不报错,返回空值
    • {}可选,但是{}能够明确定义变量名范围,帮助阅读、 解释器执行
  • 匿名变量

    • 可以认为所以语句(命令)的执行结果都存储在一个匿名 变量中,可以在其之前加上$获取其结果
  • readonly:设置变量为只读变量,更改(重定义)变量报错

  • unset:删除变量,不能删除只读变量

局部变量

局部变量:在脚本、命令中定义

  • 仅在当前shell实例中有效

    • shell变量默认为global,作用域从被定义处开始到脚本 末尾(即使在函数内部定义)
    • 显式local声明作用域局限于函数内部
  • 其他shell启动的程序不能访问局部变量

环境变量

环境变量:就是shell中的普通变量,只是这些变量往往被进程读取 用于自身初始化、设置

  • 狭义:export/declare -x声明的变量,只有这样的变量 才能默认被子进程继承
  • 广义;shell中所有的变量(包括局部变量)

环境变量设置

在shell中设置环境变量有两种方式

  • export/declare -x:设置全局(环境)变量

    • 任何在该shell设置环境变量后,启动的(子)进程都会 继承该变量
    • 对于常用、许多进程需要的环境变量应该这样设置
  • <ENV_NAME>=... cmd:设置临时环境变量

    • <ENV_NAME>=...不能被子进程继承,所以必须在其后立刻 接命令
    • 只对当前语句有效,也不能覆盖同名变量

用途

  • 环境变量是某些程序正常运行的必要条件
  • 所有程序都能访问环境变量,可用作进程通信
    • 在程序中设置环境变量,供其他进程访问变量
    • 父进程为子进程设置环境变量,供其访问

Shell变量

Shell变量:shell程序设置的特殊变量,包括环境变量、局部变量, 保证shell的正常运行

  • $0:shell执行脚本名

    • 交互式bash(即普通终端中)该参数为-bash
      • source执行脚本时,该参数可能非预期
    • 以下shell变量均不考虑$0,如
      • 函数中$0也是脚本名
      • shift无法跳过该参数
  • $1,..., $9:向脚本传递的位置参数

  • $@:脚本、函数参数列表
  • $*:脚本、函数参数字符串
  • $#:脚本、函数参数数量
  • $?:上条命令执行结果
  • $$$$:脚本进程号
  • $!:执行脚本最后一条命令

字符串

拼接

  • shell中字符默认为字符串,自动拼接

通配符

  • *:匹配任意长度字符串

    • 不包括./,必须显式匹配
  • ?:匹配一个字符

  • []:匹配出现在[]中的字符

    1
    2
    ls /[eh][to][cm]*
    # 匹配`/etc`、`/home`等
  • {}

    • 枚举全部

      1
      2
      3
      4
      5
      6
      $ mkdir {user1, user2}-{home, bin}
      # 笛卡尔积(字符串连接)
      # 等价于建立`user1-home, user1-bin, user2-home, user2-bin`
      $ echo {1..10}
      # 生成序列
      # 见`for`中`RangeIterator`部分

子串

1
2
$ file=/dir1/dir2/dir3/file.txt.bak
$ null=""

切片

  • ${<var_name>:n[:m]}:从第n开始m个字符
    • nm非负值
      • n:从0开始的下标起始
      • m切片长度缺省表示到末尾
    • nm使用0-负值表示
      • n:从0开始的负向下标起始
      • m:从0开始的负向下标终止
命令 解释 结果
${file:0:5} 提取首个字符开始的5个字符 /dir1
${file:5:5} 提取第5个字符开始的5个字符 /dir2
${file:5} 提取第5个字符开始至末尾 /dir2...
${file:0-5} 反向计算下标 t.bak
${file:0-5:0-1} 反向计算下标 t.ba
${file:5:0-2} 提取第5个字符开始至-2下标处 /dir2.../t.b

子串匹配

1
2
3
4
${<var_name>%<pattern>}
${<var_name>%%<pattern>}
${<var_name>#<pattern>}
${<var_name>##<pattern>}
  • #:去掉字符串左边最短pattern
  • ##:去掉字符串左边最长pattern
  • %:去掉字符串右边最短pattern
  • %%:去掉字符串右边最长pattern
  • 注意:var_name前不要变量标志$
  • 以上4种模式返回新值,不改变原变量值
  • 仅在pattern中使用通配符时,最短、最长匹配才有区别
命令 解释 结果
${file#*/} 去除首个/及其左边 dir2/dir3/file.txt.bak
${file##*/} 仅保留最后/右边 file.txt.bak
${file#*.} 去除首个.及其左边 txt.bak
${file##*.} 仅保留最后.右边 bak
${file%/*} 去除最后/及其右边 /dir1/dir2/dir3
${file%%*/} 去除首个/及其右边 空值
${file%*.} 去除最后.及其右边 /dir1/dir2/dir3/file.txt
${file%%*.} 去除首个.及其右边 /dir1/dir2/dir3/file.txt

替换

  • /from/to:替换首个fromto
  • //from/to:替换全部fromto
命令 解释 结果
${file/dir/path} 替换首个dirpath /path1/dir2/dir3/file.txt.bak
${file/dir/path} 替换全部dirpath /path1/path2/path3/file.txt.bak

默认值替换

  • -:变量未设置返回
  • +:变量设置返回
  • =:变量未设置返回、设置变量
  • ?:变量未设置输出至stderr
  • ::以上命令条件包括空值(空值视为未设置)

shell_variable_assignment

命令 解释 示例 结果
${井<var_name>} 获取字符串长度 ${井file} 27
${<var_name>-<default>} 变量未设置返回默认值 ${invalid-file.txt.bak} file.txt.bak
${<var_name>:-<default>} 变量未设置、空值返回默认值 ${null-file.txt.bak} file.txt.bak
${<var_name>+<default>} 变量设置返回默认值 ${file-file.txt.bak} fil.txt.bak
${<var_name>:+<default>} 变量非空返回默认值 ${file-file.txt.bak} file.txt.bak
${<var_name>=<default>} 变量未设置,返回默认值、并设置变量为默认值 ${invalid=file.txt.bak} file.txt.bak
${<var_name>:=<default>} 变量未设置、空值返回默认值、并设置变量为默认值 ${null=file.txt.bak} file.txt.bak
{$<var_name>?<default>} 变量未设置输出默认值至stderr {invalid?file.txt.bak} file.txt.bak输出至stderr
{$<var_name>:?<default>} 变量未设置、空值输出默认值至stderr {$null:?file.txt.bak} file.txt.bak输出至stderr

字符串比较

  • =, !=, -z, -n:字符串相等、不相等、为空、非空

  • 使用=比较变量是否为某字符串时,其中在两侧添加字符 保证=不为空值,否则若$test为空值,表达式报错

    1
    2
    3
    if [[ "$text"x = "text"x ]]; then
    command
    fi
  • 比较变量时要在两侧加上双引号"",否则可能报错、结果不 符合预期

数组

1
$ A=(a b c def)

取值

  • []:选择数组元素
    • [n]:返回数组第n个元素
    • [*]/[@]:返回数组全部元素
命令 解释 结果
${A[@]} 返回全部元素 a b c def
${A[*]} 同上 同上
${A[0]} 返回数组第一个元素 a
${井A[@]} 返回数组元素总数 4
${井A[*]} 同上 同上
${井A[3]} 返回数组第4个元素长度 3
A[3]=xyz 设置数组第4个元素值

数值

  • (())/[]:在其中执行整数运算
  • let:执行数值运算

规则

  • 返回的数据结果相当于存储在一个匿名变量中,使用的话需要 在之前加上$

  • 1
    2
    3
    $ a=5; b=7; c=2;
    $ echo $((a + b * $c))
    # 19
  • $((N#xx))/$[$#xx]:将其他进制数据转换为10进制

    1
    2
    $ echo $((2#110))
    # 6
  • 自增、自减运算可以在(())/[]中直接执行

    1
    2
    $ a=5; ((a++)); echo $a;
    # 6

特殊运算符

  • ~:位与
  • |:位或
  • ^:位异或
  • >>:位右移
  • <<:位左移
  • **:数值平方
  • +=, ++, -=, --, *=, \=:自变化运算符

逻辑运算

  • -eq, -ne, -ge, -le, -lt, -gt:比较
  • ==, !=, >=, <=, <, >:数值比较

文件

  • -e:目标存在
  • -f:文件为一般文件(非目录、设备)
  • -s:文件大小非0
  • -d:目标为目录
  • -b:文件为块设备(软盘、光驱)
  • -c:文件为流设备(键盘、modem、声卡)
  • -p:文件为管道
  • -h/L:目标为符号链接
  • -S:目标为Socket
  • -t:文件描述符被关联到终端
    • 一般用于检测脚本的stdin是否来自终端[ -t 0 ],或 输出是否输出至终端[ -t 1 ]
  • -r:目标是否可读权限
  • -w:目标是否可写权限
  • -x:目标是否可执行权限
  • -g:目标是否设置有set-group-id
  • -u:目标是否设置有set-user-id
  • -k:目标是否设置sticky bit
  • -O:用户是否是文件所有者
  • -G:用户是否属于文件所有组
  • -N:文件从上次读取到现在为止是否被修改
  • f1 -nt f2:文件f1f2
  • f1 -ot f2:文件f1f2
  • f1 -ef f2:文件f1f2指向相似文件实体(相同的硬链接)
Author

UBeaRLy

Posted on

2019-08-01

Updated on

2019-08-01

Licensed under

Comments