[MIT公开课(计算机教育中缺失的一课)]2.Shell工具与脚本

(该系列文章大部分内容来源于MIT课程笔记,加入了个人的理解、原笔记中没有的细节和其他的需要理解的内容,公开课地址:https://www.bilibili.com/video/BV14E411J7n2?p=1

上一讲:Overview+Shell笔记
下一讲:编辑器(Vim)



Shell 脚本

大多数shell都有自己的一套脚本语言,包括变量、控制流和自己的语法。shell脚本与其他脚本语言不同之处在于,shell脚本针对shell所从事的相关工作进行来优化。因此,创建命令流程(pipelines)、将结果保存到文件、从标准输入中读取输入,这些都是shell脚本中的原生操作,这让它比通用的脚本语言更易用。本节中,我们会专注于bash脚本,因为它最流行,应用更为广泛。

在bash中为变量赋值的语法是foo=bar,访问变量中存储的数值,其语法为 $foo。 需要注意的是,foo = bar (使用空格隔开)是不能正确工作的,因为解释器会调用程序foo 并将 = 和 bar作为参数。 总的来说,在shell脚本中使用空格会起到分割参数的作用,有时候可能会造成混淆,请务必多加检查。

Bash中的字符串通过’ 和 "分隔符来定义,但是它们的含义并不相同。以’定义的字符串为原义字符串,其中的变量不会被转义,而 "定义的字符串会将变量值进行替换:

lilhoe@LilHoedeMacBook-Pro Downloads % hsj=ad
lilhoe@LilHoedeMacBook-Pro Downloads % echo $hsj
ad
lilhoe@LilHoedeMacBook-Pro Downloads % echo "$hsj"
ad
lilhoe@LilHoedeMacBook-Pro Downloads % echo '$hsj'
$hsj
lilhoe@LilHoedeMacBook-Pro Downloads % 

bash 也支持函数,它可以接受参数并基于参数进行操作。下面这个函数是一个例子,它会创建一个函数并使用cd进入该文件夹。首先输入vim adh.sh进入文件编程模式,点击i进入修改模式:在这里插入图片描述

mcd () {
   
    mkdir -p "$1"
    cd "$1"
}

在这里插入图片描述
这里 $1 是脚本到第一个参数。与其他脚本语言不同到是,bash使用了很多特殊到变量来表示参数、错误代码和相关变量。下面是列举来其中一些变量,更完整到列表可以参考 这里

$0 - 脚本名
$1 到 $9 - 脚本到参数。
$1 是第一个参数,依此类推。
$@ - 所有参数
$# - 参数个数
$? -前一个命令到返回值
$$ - 当前脚本到进程识别码
!! - 完整到上一条命令,包括参数。常见应用:当你因为权限不足执行命令失败时,可以使用sudo !!再尝试一次。
$_ - 上一条命令的最后一个参数。如果你正在使用的是交互式shell,你可以通过按下 Esc 之后键入 .来获取这个值。

最后键入:q!退出,若文件有修改键入:wq保存退出。

通过source adh.sh指令执行adh.sh文件,看似没有事情发生,但是adh文件已经被执行。输入mcd test会从工具目录转到测试目录。

命令通常使用 STDOUT来返回输出值,使用STDERR 来返回错误及错误码,便于脚本以更加友好到方式报告错误。 返回码或退出状态是脚本/命令之间交流执行状态到方式。返回值0表示正常执行,其他所有非0的返回值都表示有错误发生。

退出码可以搭配&& (与操作符) 和 || (或操作符)使用,用来进行条件判断,决定是否执行其他程序。同一行的多个命令可以用 ; 分隔。程序 true 的返回码永远是0,false 的返回码永远是1。

另一个常见的模式是以变量的形式获取一个命令的输出,这可以通过 命令替换 (command substitution)实现。

当您通过 $( CMD ) 这样的方式来执行CMD 这个命令时,然后它的输出结果会替换掉 $( CMD ) 。例如,如果执行 for file in $(ls) ,shell首先将调用ls ,然后遍历得到的这些返回值。

还有一个冷门的类似特性是 进程替换(process substitution), <( CMD ) 会执行 CMD 并将结果输出到一个临时文件中,并将 <( CMD ) 替换成临时文件名。这在我们希望返回值通过文件而不是STDIN传递时很有用。例如, diff <(ls foo) <(ls bar) 会显示文件夹 foo 和 bar 中文件的区别。

下面这个例子展示了一部分上面提到的特性。这段脚本会遍历我们提供的参数,使用grep 搜索字符串 foobar,如果没有找到,则将其作为注释追加到文件中。将如下文件保存到example.sh中:

#!/bin/bash

echo "Starting program at $(date)" # date会被替换成日期和时间

echo "Running program $0 with $# arguments with pid $$"

for file in $@; do
    grep foobar $file > /dev/null 2> /dev/null
    # 如果模式没有找到,则grep退出状态为 1
    # 我们将标准输出流和标准错误流重定向到Null,因为我们并不关心这些信息
    if [[ $? -ne 0 ]]; then
    # -ne for "not equal", for more details see "man test"
        echo "File $file does not have any foobar, adding one"
        echo "# foobar" >> "$file"
    fi
done

在bash中进行比较时,尽量使用双方括号 [[ ]] 而不是单方括号 [ ],这样会降低犯错的几率,尽管这样并不能兼容 sh。 更详细的说明参见这里

当执行脚本时,我们经常需要提供形式类似的参数。bash使我们可以轻松的实现这一操作,它可以基于文件扩展名展开表达式。这一技术被称为shell的 通配( globbing)

通配符 - 当你想要利用通配符进行匹配时,你可以分别使用 ? 和 * 来匹配一个或任意个字符。例如,对于文件foo, foo1, foo2, foo10 和 bar, rm foo?这条命令会删除foo1 和 foo2 ,而

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值