关于shell:Shell-工具和脚本学习笔记

4次阅读

共计 3556 个字符,预计需要花费 9 分钟才能阅读完成。

写在后面:本篇内容来自于 MIT 推出的课程:计算机教育中缺失的一课,这门课程介绍了命令行、弱小的文本编辑器的应用、应用版本控制系统提供的多种个性等等。中文课程主页:https://missing-semester-cn.github.io/。

本篇为学习第二节课所做的笔记,主题是 Shell 工具和脚本,在这节课中,介绍了 bash 作为脚本语言的一些根底操作,以及几种最罕用的 shell 工具。

  • 变量赋值:foo=bar,留神两头不能增加空格
  • Bash 中的字符串通过 '"分隔符来定义,然而它们的含意并不相同。以 ' 定义的字符串为 原义字符串 ,其中的变量不会被本义,而 " 定义的字符串 会将变量值进行替换
  • 函数编写:应用 "$1"获取变量值
mcd () {
    mkdir -p "$1"
    cd "$1"
}
  • bash 中的非凡变量

    • $0 – 脚本名
    • $1  $9 – 脚本的参数$1 是第一个参数,依此类推。
    • $@ – 所有参数
    • $# – 参数个数
    • $? – 前一个命令的返回值
    • $$ – 以后脚本的过程识别码
    • !! – 残缺的上一条命令,包含参数 。常见利用:当你因为权限有余执行命令失败时,能够应用 sudo !! 再尝试一次。
    • $_ – 上一条命令的最初一个参数。如果你正在应用的是交互式 shell,你能够通过按下 Esc 之后键入 . 来获取这个值。
  • 非凡变量能够搭配短路运算符,来中断程序的运行
  • 命令替换 :以变量的模式获取一个命令的输入,当通过 $(CMD) 这样的形式来执行 CMD 这个命令时,它的输入后果会替换掉 $(CMD)。例如,如果执行 for file in $(ls),shell 首先将调用 ls,而后遍历失去的这些返回值。
  • 过程替换:还有一个冷门的相似个性是 过程替换(process substitution),<(CMD) 会执行 CMD 并将后果输入到一个临时文件中,并将 <(CMD) 替换成长期文件名。这在咱们心愿返回值通过文件而不是 STDIN 传递时很有用。例如,diff <(ls foo) <(ls bar) 会显示文件夹 foobar 中文件的区别
  • 程序示例,变量为文件名,如果文件名中蕴含“foobar”,不进行操作,否则退出”foobar“
#!/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
        # 这里的空格不能少
        echo "File $file does not have any foobar, adding one"
        echo "# foobar" >> "$file"
    fi
done
  • 批量解决文件时十分有用:bash 通配(globbing)。

    • 通配符 – 当你想要利用通配符进行匹配时,能够别离应用 ?* 来匹配一个或任意个字符
    • 花括号 {} – 当你有一系列的指令,其中蕴含一段公共子串时,能够用花括号来主动开展这些命令。这在批量挪动或转换文件时十分不便。
convert image.{png,jpg}
# 会开展为
convert image.png image.jpg

cp /path/to/project/{foo,bar,baz}.sh /newpath
# 会开展为
cp /path/to/project/foo.sh /path/to/project/bar.sh /path/to/project/baz.sh /newpath

# 也能够联合通配应用
mv *{.py,.sh} folder
# 会挪动所有 *.py 和 *.sh 文件

mkdir foo bar

# 上面命令会创立 foo/a, foo/b, ... foo/h, bar/a, bar/b, ... bar/ h 这些文件
touch {foo,bar}/{a..h}
touch foo/x bar/y
# 比拟文件夹 foo 和 bar 中蕴含文件的不同
diff <(ls foo) <(ls bar)
# 输入
# < x
# ---
# > y
  • 查看 shell 脚本中的谬误工具:shellcheck,有程序,也有插件
  • 查找帮忙:man 程序,然而输入太长,能够应用 tldr 程序,输入几个例子(十分有用!)
  • 查找文件:findfdfd 默认反对应用正则查找,更加合乎直觉。locate 应用数据库的形式更加疾速的搜寻,然而缺点是只能通过文件名来查找。
  • 查找代码:grep 有很多选项,这也使它成为一个十分全能的工具。其中我常常应用的有 -C获取查找后果的上下文(Context)-v 将对后果进行反选(Invert),也就是输入不匹配的后果。举例来说,grep -C 5 会输入匹配后果前后五行。当须要搜寻大量文件的时候,应用 -R 会递归地进入子目录并搜寻所有的文本文件。然而,咱们有很多方法能够对 grep -R 进行改良,例如使其疏忽.git 文件夹,应用多 CPU 等等。因而呈现了很多替代品:比拟罕用的是 ripgrep (rg),因为它速度快,而且用法十分合乎直觉。例子如下:
# 查找所有应用了 requests 库的文件
rg -t py 'import requests'
# 查找所有没有写 shebang 的文件(蕴含暗藏文件)rg -u --files-without-match "^#!"
# 查找所有的 foo 字符串,并打印其之后的 5 行
rg foo -A 5
# 打印匹配的统计信息(匹配的行和文件的数量)rg --stats PATTERN
  • 查找命令

    • history 拜访 shell 中输出的历史命令
    • 对于大多数的 shell 来说,能够应用 Ctrl+R 对命令历史记录进行回溯搜寻。敲 Ctrl+R 后能够输出子串来进行匹配,查找历史命令行。重复按下就会在所有搜寻后果中循环。在 zsh 中,应用方向键上或下也能够实现这项工作。
  • 导航

    • ranger
    • autojump,命令 j

习题局部

  1. ls 命令

    1. 显示所有文件:ls -a
    2. 以能够了解的格局输入:ls -lh
    3. 以最近拜访程序排序:ls -tl
  2. 编写两个 bash 函数:marco 和 polo 执行上面的操作。每当你执行 marco 时,以后的工作目录该当以某种模式保留,当执行 polo 时,无论当初处在什么目录下,都该当 cd 回到过后执行 marco 的目录。为了不便 debug,你能够把代码写在独自的文件 marco.sh 中,并通过 source marco.sh 命令,(从新)加载函数。
macro () {current="$(pwd)"
    echo "$current saved to cache"
}

polo () {
    cd "$current"
    echo "jump to $current"
}
  1. 假如您有一个命令,它很少出错。因而为了在出错时可能对其进行调试,须要破费大量的工夫重现谬误并捕捉输入。编写一段 bash 脚本,运行如下的脚本直到它出错,将它的规范输入和规范谬误流记录到文件,并在最初输入所有内容。加分项:报告脚本在失败前共运行了多少次。
#!/usr/bin/env bash

count=0
while true; do
    n=$((RANDOM % 100))

    if [[n -eq 42]]; then
        echo "Something went wrong"
        echo >&2 "The error was using magic numbers"
        echo "Program successfully ran $count times\n"
        exit 1
    fi
    ((count += 1))
    echo "ran successfully"
done

echo $count
echo "Everything went according to plan"

执行:sh [capture.sh](http://capture.sh/) 1> output 2> error; cat output; cat error

  1. 您的工作是编写一个命令,它能够递归地查找文件夹中所有的 HTML 文件,并将它们压缩成 zip 文件。留神,即便文件名中蕴含空格,您的命令也应该可能正确执行(提醒:查看 xargs 的参数 -d,译注:MacOS 上的 xargs 没有 -d,查看这个 issue)。如果您应用的是 MacOS,请留神默认的 BSD find 与 GNU coreutils 中的是不一样的。你能够为 find 增加 -print0 选项,并为 xargs 增加 -0 选项。作为 Mac 用户,您须要留神 mac 零碎自带的命令行工具和 GNU 中对应的工具是有区别的;如果你想应用 GNU 版本的工具,也能够应用 brew 来装置。
find *.html | xargs -d zip compressed.zip
  1. (进阶) 编写一个命令或脚本递归的查找文件夹中最近应用的文件。更通用的做法,你能够依照最近的应用工夫列出文件吗?
正文完
 0