The Missing Semester of Your CS Education(计算机教育中缺失的一课)

Shell 工具和脚本(Shell Tools and Scripting)


一、shell脚本

1.1、变量赋值

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

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

和其他大多数的编程语言一样,bash也支持ifcasewhile 和 for 这些控制流关键字。同样地, bash 也支持函数,它可以接受参数并基于参数进行操作。下面这个函数是一个例子,它会创建一个文件夹并使用cd进入该文件夹。

在这里我们首先调用了mcd()函数,之后调用"mkdir"命令来创建这个目录,"$1"是一种特殊变量,类似于其他语言里的"argv","argv"第一项将包含该参数。

"sourch mcd.sh"将会在我们的shell中加载并执行这个脚本。

"mcd test"我们从当前目录移动到"test"目录,

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

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

上图,"echo $?"返回0则代表程序正常执行返回,没有问题,而返回1则代表程序出现错误,"grep foorbar mcd.sh":表示从"mcd.sh"中寻找"foobar"字符串,但是该字符串不存在,故,"grep"不会输出任何内容,但是会返回1告诉我们程序发生了错误。

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

退出码可以搭配 &&(与操作符 - 在第一个命令没有错误的情况下执行第二个命令)和 ||(或操作符 - 第一个命令失败,则执行第二个命令,第一个命令成功,则跳过第二个命令(短路))使用,用来进行条件判断,决定是否执行其他程序。它们都属于短路运算符(short-circuiting)。同一行的多个命令可以用 ; 分隔。程序 true 的返回码永远是0false 的返回码永远是1

"foo=$(pwd)":该命令打印我们现在所在的当前工作目录,然后将其存储到"foo"变量中。

我们上述的命令都是将变量扩展为字符串输出,我们还有另一个"魔法"叫进程替换,它和命令替换有些相似,"cat < (ls) < (ls ..)":命令会在内部执行,然后将输出放入一个类似临时文件的东西中,并将文件标识符提供给最左边的命令。所以在这种情况下,我们正在查看这个目录,将其放入临时文件中,并对父文件夹做同样的事情,然后将两个文件连接起来。(因为一些命令并不是从标准输入流中获取输入的,而是从某些文件中获取的)

所以我们得到了两个命令连在一起的输出。

#!/bin/bashecho "Starting program at $(date)" # date会被替换成日期和时间echo "Running program $0 with $# arguments with pid $$"for file in "$@"; dogrep foobar "$file" > /dev/null 2> /dev/null# 如果模式没有找到,则grep退出状态为 1# 我们将标准输出流和标准错误流重定向到Null,因为我们并不关心这些信息if [[ $? -ne 0 ]]; thenecho "File $file does not have any foobar, adding one"echo "# foobar" >> "$file"fi
done

"$0":我们正在运行的脚本文件名。

"$#":我们给该命令参数的数量。

"$$":正在运行该命令的进程ID(PID)

"$@":它将展开为所有的参数,因此我们可以不必限定参数而只编写"$1"、"$2"、"$3",如果我们不知道有多少参数,可以将所有的参数放在那里。然后将其传递给for循环,for循环将依次创建"file"变量,并将每一个参数赋值给"file"。

"grep":在某个文件中搜索字符串

如果我们关心程序的输出,我们可以将其重定向到某个地方,以保存它或是连接其它文件。但在这里,我们需要关注错误代码,对于这个脚本,我们想知道"grep"是否运行成功。我们完全可以忽略输出,则将输出重定向到"/dev/null"(黑洞文件),它是UNIX中的一种特殊设备,你可以像写入文件一样写入数据,但它将被丢弃,"2>"用于重定向标准错误流,因为这两个流是分开的,你需要告诉Bash如何去处理它。所以在这行代码中,我们检查文件是否包含"foobar",如果包含,则返回0;如果不包含,则返回非0的错误代码。

在条件语句中,我们比较 $? 是否等于0。"-ne":"not equal"(不相等)

"echo # foobar":希望这是对文件的注释,然后我们使用">>"在文件末尾追加,因为文件名已经被传递给脚本,我们之前不知道文件名,所以我们用了"file"变量,现在要将其展开。

Bash实现了许多类似的比较操作,您可以查看 test 手册(或于终端上键入命令"man test")。 在bash中进行比较时,尽量使用双方括号 [[ ]] 而不是单方括号 [ ],这样会降低犯错的几率,尽管这样并不能兼容 sh。 更详细的说明参见这里。

下面的图片我们使用"ls"可以看到现在路径下的文件,如果我们想要显示所有后缀是".sh"的文件该怎么样呢?我们可以使用"*",即在想要显示的文件后缀前加入它,就可以完成要求。 

上图我们可以看到我们拥有以"project"开头的文件,假设我们现在只想匹配"project"后加一个字符,而并非两个字符,我们可以使用"?",它可以扩展为任何一个字符。

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

  • 通配符 - 当你想要利用通配符进行匹配时,你可以分别使用 ? 和 * 来匹配一个或任意个字符。例如,对于文件foofoo1foo2foo10 和 barrm foo?这条命令会删除foo1 和 foo2 ,而rm foo* 则会删除除了bar之外的所有文件。
  • 花括号{} - 当你有一系列的指令,其中包含一段公共子串时,可以用花括号来自动展开这些命令。这在批量移动或转换文件时非常方便。
convert image.{png,jpg}
# 会展开为
convert image.png image.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 和 *.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

假设我们在文件夹中有一个图像,我们想将其从PNG转化成JPG, 我们只需输入"convert image.{png,jpg}"即可,我们还可以输入"touch foo{}"touch一串foo,所有这些都将会被扩展。

我们还可多层操作,将它们做笛卡尔积,"touch project{1,2}/src/test/test{1,2,3}.py"如果我们有一些这样的组:"{1,2}",然后后面有{1,2,3},这将以这两个组的笛卡尔积进行扩展,并将扩展为下图所有的这些东西,我们可以快速的创建文件。

我们还可以将"*"和"{}"结合使用,我们还可以用类似区间的东西。

这将会扩展到"foo/a"、"foo/b"...所有这些组合,一直到"j",同样,对于"bar"也是如此。

那么如果我们在这两个目录创建两个不同的文件,并且演示一下之前讲过的进程替换,比如我们想检查一下这两个文件夹有哪些个文件不同,我们可以使用"diff",并让其在两个"ls"的输出间作比较。

毫无疑问,我们得到的结果是"x"存在于第一个文件夹中,"y"存在于第二个文件夹中。 

编写 bash 脚本有时候会很别扭和反直觉。例如 shellcheck 这样的工具可以帮助你定位sh/bash脚本中的错误。

注意,脚本并不一定只有用 bash 写才能在终端里调用。比如说,这是一段 Python 脚本,作用是将输入的参数倒序输出:

#!/usr/local/bin/python
import sys
for arg in reversed(sys.argv[1:]):print(arg)

内核知道去用 python 解释器而不是 shell 命令来运行这段脚本,是因为脚本的开头第一行的 shebang。

在 shebang 行中使用 env 命令是一种好的实践,它会利用环境变量中的程序来解析该脚本,这样就提高了您的脚本的可移植性。env 会利用我们第一节讲座中介绍过的PATH 环境变量来进行定位。 例如,使用了env的shebang看上去是这样的#!/usr/bin/env python

shell函数和脚本有如下一些不同点:

  • 函数只能与shell使用相同的语言,脚本可以使用任意语言。因此在脚本中包含 shebang 是很重要的。
  • 函数仅在定义时被加载,脚本会在每次被执行时加载。这让函数的加载比脚本略快一些,但每次修改函数定义,都要重新加载一次。
  • 函数会在当前的shell环境中执行,脚本会在单独的进程中执行。因此,函数可以对环境变量进行更改,比如改变当前工作目录,脚本则不行。脚本需要使用 export 将环境变量导出,并将值传递给环境变量。
  • 与其他程序语言一样,函数可以提高代码模块性、代码复用性并创建清晰性的结构。shell脚本中往往也会包含它们自己的函数定义。

"shellcheck"工具:它可以为我们提供警告、语法错误,和其他可能不正确引用或文件中错放空格的问题。例如,对于非常简单的"mcd.sh"文件,我们会得到一些错误提示,我们缺少了"shebang",如果在不同的系统上运行,可能无法正确解释它;另外,"cd"的命令可能会不正确的扩展,我们可以使用它下面给出的方法。这样做更改的效果是,如果"cd"没有正确执行,你不能"cd"进入该文件夹,因为要么你没有权限,要么其不存在,这将返回一个非0的错误代码,脚本将执行"exit",这将停止脚本的运行,而不是继续对实际不存在的地方执行命令。

二、Shell工具

2.1、查看命令如何使用

看到这里,您可能会有疑问,我们应该如何为特定的命令找到合适的标记呢?例如 ls -lmv -i 和 mkdir -p。更普遍的是,给您一个命令行,您应该怎样了解如何使用这个命令行并找出它的不同的选项呢? 一般来说,您可能会先去网上搜索答案,但是,UNIX 可比 StackOverflow 出现的早,因此我们的系统里其实早就包含了可以获取相关信息的方法。

在上一节中我们介绍过,最常用的方法是为对应的命令行添加-h 或 --help 标记。另外一个更详细的方法则是使用man 命令。man 命令是手册(manual)的缩写,它提供了命令的用户手册。

例如,man rm 会输出命令 rm 的说明,同时还有其标记列表,包括之前我们介绍过的-i。 事实上,目前我们给出的所有命令的说明链接,都是网页版的Linux命令手册。即使是您安装的第三方命令,前提是开发者编写了手册并将其包含在了安装包中。在交互式的、基于字符处理的终端窗口中,一般也可以通过 :help 命令或键入 ? 来获取帮助。

有时候手册内容太过详实,让我们难以在其中查找哪些最常用的标记和语法。 TLDR pages 是一个很不错的替代品,它提供了一些案例,可以帮助您快速找到正确的选项。

例如,自己就常常在tldr上搜索tar 和 ffmpeg 的用法。

2.2、查找文件

如果我们已经知道要查找所有名为"src"的文件,那么我们可以用"find",我们将在当前文件夹下调用"find","."表示当前文件夹,我们要让它的名称为"src",类型是文件夹,输入这个命令后,它将递归的浏览文件夹,并查找所有符合该标准的文件或文件夹。

我们还可以用它来查找特定模式的文件路径,我们希望有一些文件夹(并不在意数量),我们想要的是所有的Python脚本,所有扩展名为".py"的东西,这些都需要在名为test的文件夹下。"-type f"代表查找类型是文件。

你还可以查找修改过的文件,"-mtime"用于修改时间,在过去一天内修改过的文件,这几乎将是所有文件。

"find"不仅仅可以用于查找,我们还可以在找到这些文件时进行一些操作。所有,我们查找所有扩展名为"tmp"的文件,并且我们告诉"find",在此文件中的所有文件我们将对其执行"rm"命令。

# 删除全部扩展名为.tmp 的文件
find . -name '*.tmp' -exec rm {} \;
# 查找全部的 PNG 文件并将其转换为 JPG
find . -name '*.png' -exec convert {} {}.jpg \;

如果我们只想匹配以"tmp"结尾的内容,你可以使用"fd",这是一个更短的命令,它默认使用正则表达式,甚至还能忽略搜索你的git文件。

# 查找所有名称为src的文件夹
find . -name src -type d
# 查找所有文件夹路径中包含test的python文件
find . -path '*/test/*.py' -type f
# 查找前一天修改的所有文件
find . -mtime -1
# 查找所有大小在500k至10M的tar.gz文件
find . -size +500k -size -10M -name '*.tar.gz'

fd 就是一个更简单、更快速、更友好的程序,它可以用来作为find的替代品。它有很多不错的默认设置,例如输出着色、默认支持正则匹配、支持unicode并且我认为它的语法更符合直觉。以模式PATTERN 搜索的语法是 fd PATTERN

大多数人都认为 find 和 fd 已经很好用了,但是有的人可能想知道,我们是不是可以有更高效的方法,例如不要每次都搜索文件而是通过编译索引或建立数据库的方式来实现更加快速地搜索。

这就要靠 locate 了。 locate 使用一个由 updatedb负责更新的数据库,在大多数系统中 updatedb 都会通过 cron (Cron是一种在Unix、Linux和类Unix操作系统中用于定期运行任务的工具。它允许用户指定一个或多个命令或脚本,并设置在指定时间或周期运行这些命令或脚本的方式。)每日更新。这便需要我们在速度和时效性之间作出权衡。而且,find 和类似的工具可以通过别的属性比如文件大小、修改时间或是权限来查找文件,locate则只能通过文件名。 这里有一个更详细的对比。

"locate":只会查找你的文件系统中包含你想要的子字符串的路径。该命令找路径的速度很快,因为它已经在此上构建了一个系统,为了使其保持更新,我们使用"updatedb"命令来更新数据库。

如果我们想查找文件的内容,可以使用之前提到的"grep"命令。

如果你想要在再次递归的搜索当前结构,并查找更多文件,怎么办?我们可以使用"find"和"-exec"。但其实,"grep"有"-R"标志,它将遍历整个目录。

2.3、查找代码

查找文件是很有用的技能,但是很多时候您的目标其实是查看文件的内容。一个最常见的场景是您希望查找具有某种模式的全部文件,并找它们的位置。

为了实现这一点,很多类UNIX的系统都提供了grep命令,它是用于对输入文本进行匹配的通用工具。它是一个非常重要的shell工具,我们会在后续的数据清理课程中深入的探讨它。

grep 有很多选项,这也使它成为一个非常全能的工具。其中我经常使用的有 -C :获取查找结果的上下文(Context);-v 将对结果进行反选(Invert),也就是输出不匹配的结果。举例来说, grep -C 5 会输出匹配结果前后五行。当需要搜索大量文件的时候,使用 -R 会递归地进入子目录并搜索所有的文本文件。

但是,我们有很多办法可以对 grep -R 进行改进,例如使其忽略.git 文件夹,使用多CPU等等。

因此也出现了很多它的替代品,包括 ack, ag 和 rg。它们都特别好用,但是功能也都差不多,我比较常用的是 ripgrep (rg) ,因为它速度快,而且用法非常符合直觉。例子如下:

rg "import requests" -t py ~/scratch # 在"scratch"文件中快速搜索导入了"requests"库
的所有的python文件# 查找所有使用了 requests 库的文件
rg -t py 'import requests'# 查找所有没有写 shebang("^#!" - 正则表达式) 的文件(包含隐藏文件 -u不忽略隐藏文件)
rg -u --files-without-match "^#!"# 查找所有的foo字符串,并打印其之后的5行
rg foo -A 5# 打印匹配的统计信息(匹配的行和文件的数量)
rg --stats PATTERN
rg "import requests" -t py -C 5 --stats ~/scratch # 它会告诉我们搜索所有内容的信息

2.4、查找shell命令

history 命令允许您以程序员的方式来访问shell中输入的历史命令。这个命令会在标准输出中打印shell中的历史命令。如果我们要搜索历史记录,则可以利用管道将输出结果传递给 grep 进行模式搜索。 history | grep find 会打印包含find子串的命令。

对于大多数的shell来说,您可以使用 Ctrl+R 对命令历史记录进行回溯搜索。敲 Ctrl+R 后您可以输入子串来进行匹配,查找历史命令行。 

Ctrl+R 可以配合 fzf 使用。fzf 是一个通用的模糊查找工具,它可以和很多命令一起使用。这里我们可以对历史命令进行模糊查找并将结果以赏心悦目的格式输出。

"历史子字符串搜索":另外一个和历史命令相关的技巧我喜欢称之为基于历史的自动补全。 这一特性最初是由 fish shell 创建的,它可以根据您最近使用过的开头相同的命令,动态地对当前的shell命令进行补全。这一功能在 zsh 中也可以使用,它可以极大的提高用户体验。 

2.5、文件夹导航

"-R"来递归的列出某个目录的结构。

"tree":更友好的打印目录结构。 

之前对所有操作我们都默认一个前提,即您已经位于想要执行命令的目录下,但是如何才能高效地在目录间随意切换呢?有很多简便的方法可以做到,比如设置alias,使用 ln -s 创建符号连接等。而开发者们已经想到了很多更为精妙的解决方案。

由于本课程的目的是尽可能对你的日常习惯进行优化。因此,我们可以使用fasd和 autojump 这两个工具来查找最常用或最近使用的文件和目录。

Fasd 基于 frecency 对文件和文件排序,也就是说它会同时针对频率(frequency)和时效(recency)进行排序。默认情况下,fasd使用命令 z 帮助我们快速切换到最常访问的目录。例如, 如果您经常访问/home/user/files/cool_project 目录,那么可以直接使用 z cool 跳转到该目录。对于 autojump,则使用j cool代替即可。

还有一些更复杂的工具可以用来概览目录结构,例如 tree, broot 或更加完整的文件管理器,例如 nnn 或 ranger。

三、练习

  1. Read man ls and write an ls command that lists files in the following manner

    • Includes all files, including hidden files
    • Sizes are listed in human readable format (e.g. 454M instead of 454279954)
    • Files are ordered by recency
    • Output is colorized

    A sample output would look like this

     -rw-r--r--   1 user group 1.1M Jan 14 09:53 bazdrwxr-xr-x   5 user group  160 Jan 14 09:53 .-rw-r--r--   1 user group  514 Jan 14 06:42 bar-rw-r--r--   1 user group 106M Jan 13 12:12 foodrwx------+ 47 user group 1.5K Jan 12 18:08 ..
    
  2. Write bash functions marco and polo that do the following. Whenever you execute marco the current working directory should be saved in some manner, then when you execute polo, no matter what directory you are in, polo should cd you back to the directory where you executed marco. For ease of debugging you can write the code in a file marco.sh and (re)load the definitions to your shell by executing source marco.sh.

  3. Say you have a command that fails rarely. In order to debug it you need to capture its output but it can be time consuming to get a failure run. Write a bash script that runs the following script until it fails and captures its standard output and error streams to files and prints everything at the end. Bonus points if you can also report how many runs it took for the script to fail.

     #!/usr/bin/env bashn=$(( RANDOM % 100 ))if [[ n -eq 42 ]]; thenecho "Something went wrong">&2 echo "The error was using magic numbers"exit 1fiecho "Everything went according to plan"
    
  4. As we covered in the lecture find’s -exec can be very powerful for performing operations over the files we are searching for. However, what if we want to do something with all the files, like creating a zip file? As you have seen so far commands will take input from both arguments and STDIN. When piping commands, we are connecting STDOUT to STDIN, but some commands like tar take inputs from arguments. To bridge this disconnect there’s the xargs command which will execute a command using STDIN as arguments. For example ls | xargs rm will delete the files in the current directory.

    Your task is to write a command that recursively finds all HTML files in the folder and makes a zip with them. Note that your command should work even if the files have spaces (hint: check -d flag for xargs).

    If you’re on macOS, note that the default BSD find is different from the one included in GNU coreutils. You can use -print0 on find and the -0 flag on xargs. As a macOS user, you should be aware that command-line utilities shipped with macOS may differ from the GNU counterparts; you can install the GNU versions if you like by using brew.

  5. (Advanced) Write a command or script to recursively find the most recently modified file in a directory. More generally, can you list all files by recency?

习题解答

  1. 阅读 man ls ,然后使用ls 命令进行如下操作:

    • 所有文件(包括隐藏文件)
    • 文件打印以人类可以理解的格式输出 (例如,使用454M 而不是 454279954)
    • 文件以最近访问顺序排序
    • 以彩色文本显示输出结果

    典型输出如下:

     -rw-r--r--   1 user group 1.1M Jan 14 09:53 bazdrwxr-xr-x   5 user group  160 Jan 14 09:53 .-rw-r--r--   1 user group  514 Jan 14 06:42 bar-rw-r--r--   1 user group 106M Jan 13 12:12 foodrwx------+ 47 user group 1.5K Jan 12 18:08 ..
    
  2. 编写两个bash函数 marco 和 polo 执行下面的操作。 每当你执行 marco 时,当前的工作目录应当以某种形式保存,当执行 polo 时,无论现在处在什么目录下,都应当 cd 回到当时执行 marco 的目录。 为了方便debug,你可以把代码写在单独的文件 marco.sh 中,并通过 source marco.sh命令,(重新)加载函数。

  3. 假设您有一个命令,它很少出错。因此为了在出错时能够对其进行调试,需要花费大量的时间重现错误并捕获输出。 编写一段bash脚本,运行如下的脚本直到它出错,将它的标准输出和标准错误流记录到文件,并在最后输出所有内容。 加分项:报告脚本在失败前共运行了多少次。

     #!/usr/bin/env bashn=$(( RANDOM % 100 ))if [[ n -eq 42 ]]; thenecho "Something went wrong">&2 echo "The error was using magic numbers"exit 1fiecho "Everything went according to plan"
    
  4. 本节课我们讲解的 find 命令中的 -exec 参数非常强大,它可以对我们查找的文件进行操作。但是,如果我们要对所有文件进行操作呢?例如创建一个zip压缩文件?我们已经知道,命令行可以从参数或标准输入接受输入。在用管道连接命令时,我们将标准输出和标准输入连接起来,但是有些命令,例如tar 则需要从参数接受输入。这里我们可以使用xargs 命令,它可以使用标准输入中的内容作为参数。 例如 ls | xargs rm 会删除当前目录中的所有文件。

    您的任务是编写一个命令,它可以递归地查找文件夹中所有的HTML文件,并将它们压缩成zip文件。注意,即使文件名中包含空格,您的命令也应该能够正确执行(提示:查看 xargs的参数-d,译注:MacOS 上的 xargs没有-d,查看这个issue)

    如果您使用的是 MacOS,请注意默认的 BSD find 与 GNU coreutils 中的是不一样的。你可以为find添加-print0选项,并为xargs添加-0选项。作为 Mac 用户,您需要注意 mac 系统自带的命令行工具和 GNU 中对应的工具是有区别的;如果你想使用 GNU 版本的工具,也可以使用 brew 来安装。

  5. (进阶)编写一个命令或脚本递归的查找文件夹中最近使用的文件。更通用的做法,你可以按照最近的使用时间列出文件吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/14582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于灰狼优化算法优化RBF(GWO-RBF)的数据回归预测(多输入多输出)

代码原理及流程 基于灰狼优化算法优化多输入多输出&#xff08;MIMO&#xff09;的RBF神经网络的数据回归预测&#xff0c;可以采取以下步骤&#xff1a; 1. 数据准备&#xff1a;准备包含多个输入特征和多个输出目标的数据集&#xff0c;确保数据已经经过预处理和归一化。 …

CSS基础(第二天)

Emmet语法 快速生成HTML结构语法 1. 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab 键&#xff0c; 就可以生成 <div></div> 2. 如果想要生成多个相同标签 加上 * 就可以了 比如 div*3 就可以快速生成3个div 3. 如果有父子级关系的标签&#xff0c;可以…

算法刷题笔记 数的范围(C++实现)(二分法重要例题)

文章目录 题目描述题目思路题目代码&#xff08;C&#xff09;题目感想 题目描述 给定一个按照升序排列的长度为n的整数数组&#xff0c;以及q个查询。对于每个查询&#xff0c;返回一个元素k的起始位置和终止位置&#xff08;位置从0开始计数&#xff09;。如果数组中不存在该…

自动化测试--利用pytest实现整条业务链路测试

​ 概述 前面一章讲解了单个接口的测试&#xff0c;但是实际项目中&#xff0c;因为权限和登录状态的限制&#xff0c;大部分接口没办法直接访问到&#xff0c;这时候我们想访问到一个系统的接口&#xff0c;就需要模拟用户登录拿到用户的token和所拥有的权限之后再将这些信息…

vivado2020.2创建hls仿真工程实现led闪烁

下载vivado2020.2后会有这个出现在桌面 点击进入创建工程&#xff0c;这里注意不要有前面的\我再复制的时候复制错了导致创建失败 按f光标就会跳转到下一个f开头的函数处&#xff0c;要查找其他函数也同理 生成了一个synthesis summary文件 找到目录下生成的.v文件 an 点…

Pod进阶——资源限制以及探针检查

目录 一、资源限制 1、资源限制定义&#xff1a; 2、资源限制request和limit资源约束 3、Pod和容器的资源请求和限制 4、官方文档示例 5、CPU资源单位 6、内存资源单位 7、资源限制实例 ①编写yaml资源配置清单 ②释放内存&#xff08;node节点&#xff0c;以node01为…

有些错误,常犯常新、常新常犯:记录一个使用element-plus的tooltip组件的错误

使用element-plus的tooltip组件&#xff0c;最开始的写法是这样的&#xff1a; <el-tooltipclass"box-item"effect"dark"content"tooltip content" ><el-button v-if"isDisabled" :underline"false" type"pr…

【C语言】程序员自我修养之文件操作

【C语言】程序员自我修养之文件操作 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C语言学习之路 文章目录 【C语言】程序员自我修养之文件操作前言一.文件介绍1.1为什么使用文件1.2文件分类1.3二进制文件和文本文件 二.文件的打开和关闭2.…

桌面藏线大法

1有线改无线&#xff1a; 蓝牙鼠标 蓝牙键盘 蓝牙耳机 2将排插贴到桌子底下 购物软件上搜 3断舍离 不要的电子产品统统扔掉 4 洞洞板和挂钩 这个不用介绍了

暴雨信息液冷计算解决方案亮相CCIG 2024

5月24日&#xff0c;2024中国图象图形大会&#xff08;CCIG&#xff09;在陕西西安正式开幕。作为涵盖图像图形各专业领域的综合性的全国性学术会议&#xff0c;CCIG面向开放创新、交叉融合的发展趋势&#xff0c;为图像图形相关领域的专家学者和产业界的同仁&#xff0c;搭建了…

Java+Spring+ MySQL + MyCat云HIS有哪些优势?智慧医疗云(HIS)低成本与安全保障的完美结合

JavaSpring MySQL MyCat云HIS有哪些优势&#xff1f;智慧医疗云(HIS)低成本与安全保障的完美结合 云HIS的优点包括节省成本、便捷高效、稳妥安全等。通过云HIS&#xff0c;医疗机构无需在本地建立机房、购买服务器和应用软件&#xff0c;降低了硬件和人力成本。同时&#xff0…

虚拟化介绍

虚拟化介绍 概述概念特点优势实现手段 虚拟化架构概述寄居虚拟化架构裸金属虚拟化架构操作系统虚拟化架构混合虚拟化架构几种虚拟化架构的比较虚拟化架构与虚拟化技术的关系 虚拟化技术分类服务器虚拟化技术分类 存储虚拟化技术分类网络虚拟化技术分类 服务器虚拟化技术处理器虚…

开源软件 | 一文彻底搞懂许可证的定义、起源、分类及八大主流许可证,让你选型不再头疼

为什么开源软件会存在许可证&#xff0c;许可证的起源与产生目的是为了解决什么问题&#xff1f;许可证的定义又是怎样的&#xff1f;什么是Copyleft&#xff0c;与Copyright有何区别&#xff1f;开源软件常见的许可证有哪些&#xff1f;这些许可证都有什么特点&#xff1f;接下…

Zabbix实现7x24小时架构监控

上篇&#xff1a;https://blog.csdn.net/Lzcsfg/article/details/138774511 文章目录 Zabbix功能介绍Zabbix平台选择安装Zabbix监控端部署MySQL数据库Zabbix参数介绍登录Zabbix WEBWEB界面概览修改WEB界面语言添加被控主机导入监控模板主机绑定模板查看主机状态查看监控数据解…

代码随想录算法训练营第三十四天 | 理论基础、455.分发饼干、376、摆动序列、53.最大子序和

目录 理论基础 455.分发饼干 思路 代码 376.摆动序列 思路 代码 53.最大子序和 思路 代码 理论基础 代码随想录 455.分发饼干 代码随想录 思路 可以是大饼干优先满足大胃口&#xff0c;也可以是小饼干优先满足小胃口。 代码 class Solution:def findContentChildre…

ArkUI-X开发指南:【SDK配置和构建说明】

ArkUI-X SDK配置和构建说明 ArkUI-X SDK是ArkUI-X开源项目的编译产物&#xff0c;可将ArkUI-X SDK集成到现有Android和iOS应用工程中&#xff0c;使开发者基于一套ArkTS主代码&#xff0c;就可以构建支持多平台的精美、高性能应用。SDK内容包含ArkUI跨平台运行时&#xff0c;组…

B站自动回复插件_无需千粉,轻松适配引流拉新资源分享

项目介绍 B站关键词自动回复插件&#xff0c;无需千粉&#xff0c; 很适合做流量做引流做私欲的朋友&#xff0c; 前期没有千粉是无法开启官方自动回复的&#xff0c; 适当的情况下可以用这个插件顶一下&#xff0c; 三联好评领取资源的打法真的超级涨粉&#xff0c; 感谢插件…

HAL库点LED灯

文章目录 一、创建CubeMX项目操作步骤1.STM32CubeMX创建工程2.选择芯片3.Pinout & Configuration配置4.Clock Configuration配置5.Project Manager配置 二、实验&#xff08;一&#xff09;LED流水灯1.Keil修改代码2.实验现象3.keil波形仿真 &#xff08;二&#xff09;2只…

变量命名的艺术:让你的代码更具可读性

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;为何变量命名如此重要&#xff1f; 二、变量命名的基本规则 1. 避免数…

卷爆短剧出海:五大关键,由AIGC重构

短剧高温下&#xff0c;谈谈AIGC的助攻路线。 短剧&#xff0c;一个席卷全球的高温赛道。 以往只是踏着霸总题材&#xff0c;如今&#xff0c;内容循着精品化、IP化的自然发展风向&#xff0c;给内容、制作、平台等产业全链都带来新机&#xff0c;也让短剧消费走向文化深处&am…