读书笔记-Bash(网道(WangDoc.com)教程)

学习资料来自于 https://wangdoc.com/bash/grammar.html
下列按原章节名称记录

bash启动conda的时候需要

source /Users/admin/anaconda3/etc/profile.d/conda.sh
conda activate test
不然conda activate会报错

1 简介

2 基本语法

  • echo -n 取消末尾的回车 -e 会解释\n 这种,否则直接打印
  • ls -是短参数 --是长参数

3 模式拓展

另一个需要注意的地方是,大括号内部的逗号前后不能有空格。否则,大括号扩展会失效。

略读, 主要是一些正则和小技巧,难记

$ echo {a..c}{1..3}
a1 a2 a3 b1 b2 b3 c1 c2 c3

4 引号和转义

  • 单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符,比如星号(*)、美元符号($)、反斜杠(\)等。
  • 双引号: 三个特殊字符除外:美元符号($)、反引号(`)和反斜杠(\)。这三个字符在双引号之中,依然有特殊含义,会被 Bash 自动扩展。
  • 双引号的另一个常见的使用场合是,文件名包含空格。这时就必须使用双引号(或单引号),将文件名放在里面。
  • 双引号会原样保存多余的空格。
  • 双引号还有一个作用,就是保存原始命令的输出格式。如echo "$(cal)"

5 变量

env命令或printenv命令,可以显示所有环境变量。
set命令可以显示所有变量(包括环境变量和自定义变量),以及所有的 Bash 函数。
unset命令用来删除一个变量。
export命令用来向子 Shell 输出变量。export NAME=value上面命令执行后,当前 Shell 及随后新建的子 Shell,都可以读取变量$NAME。

  • 等号左边是变量名,右边是变量句号。等号两边不能有空格
  • 事实上,读取变量的语法$foo,可以看作是${foo}的简写形式。
  • 如果变量的值本身也是变量,可以使用${!varname}的语法,读取最终的值。
  • 特殊变量:
    (1)$?为上一个命令的退出码,用来判断上一个命令是否执行成功。返回值是0,表示上一个命令执行成功;如果是非零,上一个命令执行失败。
    (2)$$为当前 Shell 的进程 ID。
    (3)$_为上一个命令的最后一个参数。
    (4)$!为最近一个后台执行的异步命令的进程 ID。
    (5)$0为当前 Shell 的名称(在命令行直接执行时)或者脚本名(在脚本中执行时)。
    (6)$-为当前 Shell 的启动参数。
    (7)$#表示脚本的参数数量,$@表示脚本的参数值,参见脚本一章。

变量的默认值

${varname:-word}
${varname:=word}
${varname:+word}
${varname:?message}

declare 命令: declare命令可以声明一些特殊类型的变量,为变量设置一些限制,比如声明只读类型的变量和整数类型的变量。
readonly 命令: readonly命令等同于declare -r,用来声明只读变量,不能改变变量值,也不能unset变量。
let 命令:let命令声明变量时,可以直接执行算术表达式。


6 字符串操作

字符串的长度 ${#varname}

子字符串 ${varname:offset:length}  如果省略length,则从位置offset开始,一直返回到字符串的结尾。  可负数语法

搜索和替换

(1)字符串头部的模式匹配。 
# 如果 pattern 匹配变量 variable 的开头,
# 删除最短匹配(非贪婪匹配)的部分,返回剩余部分
${variable#pattern}
# 如果 pattern 匹配变量 variable 的开头,
# 删除最长匹配(贪婪匹配)的部分,返回剩余部分
${variable##pattern}
--
如果要将头部匹配的部分,替换成其他内容,采用下面的写法。
# 模式必须出现在字符串的开头
${variable/#pattern/string}
# 示例
$ foo=JPG.JPG
$ echo ${foo/#JPG/jpg}
jpg.JPG

(2)字符串尾部的模式匹配。
# 如果 pattern 匹配变量 variable 的结尾,
# 删除最短匹配(非贪婪匹配)的部分,返回剩余部分
${variable%pattern}
# 如果 pattern 匹配变量 variable 的结尾,
# 删除最长匹配(贪婪匹配)的部分,返回剩余部分
${variable%%pattern}
如果要将尾部匹配的部分,替换成其他内容,采用下面的写法。
# 模式必须出现在字符串的结尾
${variable/%pattern/string}
# 示例
$ foo=JPG.JPG
$ echo ${foo/%JPG/jpg}
JPG.jpg

(3)任意位置的模式匹配。

# 如果 pattern 匹配变量 variable 的一部分,
# 最长匹配(贪婪匹配)的那部分被 string 替换,但仅替换第一个匹配
${variable/pattern/string}
# 如果 pattern 匹配变量 variable 的一部分,
# 最长匹配(贪婪匹配)的那部分被 string 替换,所有匹配都替换
${variable//pattern/string}
前面提到过,这个语法还有两种扩展形式。
# 模式必须出现在字符串的开头
${variable/#pattern/string}
# 模式必须出现在字符串的结尾
${variable/%pattern/string}
改变大小写
# 转为大写
${varname^^}
# 转为小写
${varname,,}

8 Bash 的算术运算

  • ((...))语法可以进行整数的算术运算。会自动忽略内部的空格,只要算术结果不是0,命令就算执行成功。支持加减乘 整除 余数 自增自减以及指数(**)
    $((...))的圆括号之中,不需要在变量名之前加上$,不过加上也不报错。使用不存在的变量,会当作0处理。
    最后,$[...]是以前的语法,也可以做整数运算,不建议使用。
  • 算术表达式$((...))可以执行赋值运算。
  • expr命令支持算术运算,可以不使用((...))语法。
  • let命令用于将算术运算的结果,赋予一个变量。 这个式子里面不能有空格

9 Bash 行操作

  • !e表示找出操作历史之中,最近的那一条以e开头的命令并执行。 (!string语法只会匹配命令,不会匹配参数。所以!echo H不会执行echo Hello World,而是会执行echo Goodbye,并把参数H附加在这条命令之后。同理,!echo H G也是等同于echo Goodbye命令之后附加H G)
由于!string语法会扩展成以前执行过的命令,所以含有!的字符串放在双引号里面,必须非常小心,如果它后面有非空格的字符,就很有可能报错。
$ echo "I say:\"hello!\""
bash: !\: event not found
上面的命令会报错,原因是感叹号后面是一个反斜杠,Bash 会尝试寻找,以前是否执行过反斜杠开头的命令,一旦找不到就会报错。解决方法就是在感叹号前面,也加上反斜杠。
$ echo "I say:\"hello\!\""
I say:"hello\!"
* !$:代表上一个命令的最后一个参数。
* !*:代表上一个命令的所有参数,即除了命令以外的所有部分。
* ^string1^string2:执行最近一条包含string1的命令,将其替换成string2。

9 堆栈目录

  • cd - 可以返回上一次的目录
  • pushd,popd 记忆多级目录 但是好像是相对路径奇怪, 别用
  • dirs 命令 显示堆栈

10 脚本入门

  • Shebang 行: #!balabala 写上的话, 可以直接./sh文件, 不然就要/bin/sh ./script.sh 这样子执行
  • env 命令
  • shift 命令
  • getopts 命令
  • 配置项参数终止符 --
  • source命令最大的特点是在当前 Shell 执行脚本,不像直接执行脚本时,会新建一个子 Shell。所以,source命令执行脚本时,不需要export变量。

11 read命令

  • 如果read命令之后没有定义变量名,那么环境变量REPLY会包含所有的输入。
  • read命令除了读取键盘输入,可以用来读取文件。
#!/bin/bash
filename='/etc/hosts'
while read myline
do
  echo "$myline"
done < $filename

上面的例子通过read命令,读取一个文件的内容。done命令后面的定向符<,将文件内容导向read命令,每次读取一行,存入变量myline,直到文件读取完毕。

  • 参数:
    -t参数,设置了超时的秒数
    -p参数指定用户输入的提示信息。
    -a参数把用户的输入赋值给一个数组,从零号位置开始。
    -n参数指定只读取若干个字符作为变量值,而不是整行读取。
  • read命令读取的值,默认是以空格分隔。可以通过自定义环境变量IFS(内部字段分隔符,Internal Field Separator 的缩写),修改分隔标志。

12 条件判断

if结构的判断条件,一般使用test命令,有三种形式。

# 写法一
test expression
# 写法二
[ expression ]
# 写法三
[[ expression ]]
上面三种形式是等价的,但是第三种形式还支持正则判断,前两种不支持。

注意,第二种和第三种写法,[和]与内部的表达式之间必须有空格。 实际上,[这个字符是test命令的一种简写形式,可以看作是一个独立的命令,这解释了为什么它后面必须有空格。

  • 注意,test命令内部的>和<,必须用引号引起来(或者是用反斜杠转义)。否则,它们会被 shell 解释为重定向操作符。
  • [[ string1 =~ regex ]] 正则表达式
  • [ -n string ]:如果字符串string的长度大于零,则判断为真。
  • [ -z string ]:如果字符串string的长度为零,则判断为真。
  • AND运算:符号&&,也可使用参数-a。 (没有AND吧)
  • OR运算:符号||,也可使用参数-o。
  • NOT运算:符号!。

case结构

case结构用于多值判断,可以为每个值指定对应的命令,跟包含多个elif的if结构等价,但是语义更好。它的语法如下。
case expression in
  pattern )
    commands ;;
  pattern )
    commands ;;
  ...
esac

13 循环

  • while 循环
while condition; do
  commands
done

until 循环与while相反

  • for
for variable in list; do
  commands
done

in list的部分可以省略,这时list默认等于脚本的所有参数$@。但是,为了可读性,最好还是不要省略

for循环还支持 C 语言的循环语法。

for (( expression1; expression2; expression3 )); do
  commands
done

14 函数

# 第一种  不能省略小括号()
fn() {
  # codes
}

# 第二种 小括号可选
function fn() {
  # codes
}

15 数组

  • 创建ARRAY[INDEX]=value 或者 ARRAY=(value1 value2 ... valueN)
  • $ echo ${array[i]} # i 是索引
  • @和*是数组的特殊索引,表示返回数组的所有成员。
  • 一般把${activities[@]}放在双引号之中。 ${activities[*]}不放在双引号之中,跟${activities[@]}不放在双引号之中是一样的。 ${activities[*]}放在双引号之中,所有成员就会变成单个字符串返回。
  • 数组的长度 ${#array[*]} ${#array[@]}
  • 提取数组序号 ${!array[@]}或${!array[*]},可以返回数组的成员序号,即哪些位置是有值的。
  • 提取数组成员 ${array[@]:position:length}的语法可以提取数组成员。
  • 数组末尾追加成员,可以使用+=赋值运算符

16 set 命令,shopt 命令

posted @ 2021-10-13 23:34  种树人  阅读(212)  评论(0编辑  收藏  举报