当前位置: 首页 > Linux

ShellToolsandScripts-StudyNotes

时间:2023-04-06 20:57:23 Linux

写在前面:本文来自麻省理工学院开设的课程:AMissingLessoninComputerEducation。本课程介绍了命令行、功能强大的文本编辑器的使用,以及版本控制系统提供的各种功能等等。中文课程主页: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命令时,其输出将替换$(命令)。例如,如果您执行forfilein$(ls),shell将首先调用ls然后迭代这些返回值。进程替换:另一个不受欢迎的特性是进程替换,<(CMD)会执行CMD并将结果输出到一个临时文件,将<(CMD)替换为临时文件名。当我们希望通过文件而不是STDIN传递返回值时,这很有用。例如,diff<(lsfoo)<(lsbar)将显示文件夹foo和bar中的文件之间的差异。程序示例,变量为文件名,如果文件名中包含“foobar”,则不执行任何操作,否则添加“foobar”#!/bin/bashecho"Startingprogramat$(date)"#date将被替换带有日期和时间echo"Runningprogram$0with$#argumentswithpid$$"forfilein"$@";dogrepfoobar"$file">/dev/null2>/dev/null#grepexitstatusifpatternnotfoundFor1#我们将标准输出流和标准错误流重定向到Null,因为我们不关心这个如果[[$?-ne0]];then#这里不能少空格echo"File$filedoesnothaveanyfoobar,addingone"echo"#foobar">>"$file"fidone对批处理文件很有用:bashglobbing。通配符-当你想使用通配符进行匹配时,你可以使用?和*分别匹配一个或任意数量的字符。大括号{}-当您有一系列包含公共子字符串的命令时,您可以使用大括号自动扩展命令。这在批量移动或转换文件时非常方便。convertimage.{png,jpg}#将扩展为convertimage.pngimage.jpgcp/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和*.shfilemkdirfoobar#下面的命令会创建foo/a,foo/b,...foo/h,bar/a,bar/b,...bar/h这些文件touch{foo,bar}/{a..h}touchfoo/xbar/y#比较文件夹foo和bardiff<(lsfoo)<(lsbar)#output#ycheckinshellscript错误的工具:shellcheck,有程序和插件可以找到帮助:man程序,但是输出太长,可以用tldr程序输出几个例子(很有用!)找文件:findandfd,fd默认支持正则搜索,比较直观。locate使用数据库方式查找速度更快,缺点是只能按文件名查找。查找代码:grep有很多选项,这也使它成为一个非常通用的工具。其中,我经常使用-C:获取搜索结果的上下文(Context);-v将结果倒置(Invert),即输出不匹配的结果。例如,grep-C5将在匹配前后打印五行。搜索大量文件时,使用-R递归进入子目录,搜索所有文本文件。但是,我们可以通过多种方式改进grep-R,例如让它忽略.git文件夹、使用多个CPU等等。因此,出现了许多替代方案:ripgrep(rg)更常用,因为它速度快,而且使用起来非常直观。示例如下:#查找所有使用requests库的文件rg-tpy'importrequests'#查找所有没有shebang的文件(包括隐藏文件)rg-u--files-without-match"^#!"#查找所有foo字符串,并打印其后的5行rgfoo-A5#打印匹配统计信息(匹配行数和文件数)rg--statsPATTERNsearchcommandhistory访问在shell中输入的历史命令forlarge对于大多数shell,您可以使用Ctrl+R执行命令历史记录的回溯搜索。按Ctrl+R后,可以输入一个子串来匹配搜索历史命令行。反复按可循环浏览所有搜索结果。在zsh中,使用向上或向下箭头键也可以完成这项工作。导航到rangerautojump,命令j练习部分ls命令显示所有文件:ls-a以可理解的格式输出:ls-lh按最近访问的顺序排序:ls-tl编写两个bash函数:marco和polo以执行以下操作。每当你执行marco时,当前工作目录应该以某种形式保存下来,而当polo执行时,无论你现在在什么目录,你都应该cd回到当时执行marco的目录。为了调试方便,可以将代码写在单独的文件marco.sh中,通过sourcemarco.sh命令(重新)加载函数。macro(){current="$(pwd)"echo"$currentsavedtocache"}polo(){cd"$current"echo"jumpto$current"}假设你有一个很少出错的命令。因此需要花费大量时间来重现错误并捕获输出,以便在出错时能够进行调试。编写一个运行以下脚本的bash脚本,直到它出错,将其stdout和stderr流记录到文件,并在最后输出所有内容。奖励:报告脚本在失败前运行了多少次。#!/usr/bin/envbashcount=0whiletrue;做n=$((RANDOM%100))如果[[n-eq42]];thenecho"Somethingwentwrong"echo>&2"Theerrorwasusingmagicnumbers"echo"程序成功运行$count次\n"exit1fi((count+=1))echo"运行成功"doneecho$countecho"Everything按计划进行”执行:sh[capture.sh](http://capture.sh/)1>输出2>错误;猫输出;caterror你的任务是编写一个命令,递归地查找一个文件夹中的所有HTML文件,并将它们压缩成一个zip文件。请注意,即使文件名包含空格,您的命令也应该正确执行(提示:请参阅xargs的参数-d,注解:MacOS上的xargs没有-d,请参阅此问题)。如果您使用的是MacOS,请注意默认的BSD查找与GNUcoreutils中的不同。您可以将-print0选项添加到find和-0选项到xargs。作为Mac用户,需要注意mac系统自带的命令行工具和GNU中对应工具的区别;如果你想使用该工具的GNU版本,你也可以使用brew来安装它。找到*.html|xargs-dzipcompressed.zip(高级)编写命令或脚本以递归方式查找文件夹中最近使用的文件。更一般地说,您可以按最近使用的时间列出文件吗?