Shell Tools and Scripting

Shell Tools and Scripting

变量 函数

在shell中要注意空格的使用,尤其是在进行与名字字符串中带有空格的文件有关的操作时。
"$ variable name"可以使用变量。
source function可以在shell中执行函数,然后function folder/file就可以检验了。
$0是脚本名称,$?获取上一个命令的错误代码,$_获取上一个命令参数,例如文件或文件夹等,$#给出的参数数量,$$获取pid(process id),$@扩展到所有参数。
常见的退出状态码示例:

  • 1: 一般表示命令执行时出现了错误。
  • 2: 可能表示命令使用不正确,例如参数错误。
  • 127: 表示命令未找到。
  • 126: 表示命令找到,但无法执行(例如没有执行权限)。

    !!表示获取上一段命令,例如上一段命令执行结果是没有管理员权限,那么可以sudo !!来解决。

运算符

||或,&&与,;分隔多个命令,顺序执行。
$(command)也可以代表相应的输出内容,cat <(command)也可以实现输出内容。

/dev/null

在类Unix系统中是一个特殊的设备文件,常被称为“空设备”或“比特桶”。你可以把它想象成一个无底洞,任何写入到它的数据都会被丢弃,而从它读取数据永远只会得到一个空的回应。
/dev/null 的作用

  • 丢弃输出: 当你执行一个命令,但不想看到它的输出结果时,可以将输出重定向到 /dev/null。这在自动化脚本或批量处理任务中非常常见。
  • 抑制错误信息: 某些命令执行时可能会产生错误信息。如果这些错误信息对你来说无关紧要,可以将错误信息重定向到 /dev/null。
  • 创建空文件: 可以通过将特定内容写入 /dev/null 来创建一个空文件。
    例如:find / -name "*.tmp" -delete > /dev/null 2>&1这条命令会查找系统中所有以 .tmp 结尾的文件并删除,同时将命令的标准输出和标准错误输出都重定向到 /dev/null,避免在终端显示任何信息。2>&1这是一个在 Shell 脚本中经常用到的重定向符号,用于 将标准错误输出重定向到标准输出。**2>&1 的意思就是:** 把标准错误输出(2)重定向到标准输出(1)。也就是说,原本应该显示在终端上的错误信息,现在也会和正常的输出信息一起显示。
  • 标准输出(stdout): 通常是显示在终端上的输出信息,用数字 1 表示。
  • 标准错误输出(stderr): 通常是显示在终端上的错误信息,用数字 2 表示。

查看、修改文件

*.sh是大多数sehll文件扩展名。
ls filename?可以查看相应问号位数名字的文件。
convert filename.{png.jpg}可以把图片格式从png转化成jpg,也可以加名字序号。
touch {folder1,folder2}/{file1..filen}可以遍历这两个文件夹中的所有名字中含有某个字符的文件。
touch 命令是一个常用的 Linux/Unix 命令,主要用于 修改文件的时间戳创建新文件
mv -i 命令在移动或重命名文件时会 先询问用户,以避免误操作导致数据丢失。
convert可用于转换图片,ffmep可用于处理视频。

shebang

/usr/bin/env: 这部分告诉系统使用 env 命令来查找指定的可执行程序。env 命令会搜索当前用户的环境变量 PATH,找到第一个匹配的程序。
例如:

1
2
#!/usr/bin/env python3
print("Hello, world!")

用系统环境中的 Python3 解释器来执行这个脚本。

调试 查找

shellcheck *.sh检查警告和语法错误等。
tldr command 查询命令用法,是一个为命令行工具提供简明易懂的使用说明的工具。它从冗长的 man 手册中提取出最常用的用法和示例,让用户能快速上手各种命令。
findfd用于查找文件名字,locate用于查找并列出所有,grep用于查找文件或文件夹中的具体内容,rg是ripgrep的缩写,是比grep更快的文本搜索工具,fzf模糊查找。
例如:rg -U --files-without-match "^#\!" -t sh表示在当前目录及其子目录中,查找所有的 shell 脚本文件(.sh),并找出那些第一行不是以 #! 开头的的文件。其中^: 表示行首。#: 匹配字符#。\!: 匹配字符 !。
Ctrl+R可以查找历史中出现要查找的字符的代码,每按一次就出现一条。
zsh可以提供历史推荐代码。
treebroot都是很好的文件搜索和管理工具。

课后练习

1、要求我们使用 ls 命令,并通过添加不同的参数来实现以下功能:

  • 显示所有文件(包括隐藏文件)
  • 以人类可读的格式显示文件大小
  • 按照文件访问时间排序
  • 使用彩色输出
    答:ls -lah –color=auto
    -l 以长格式显示;-a 显示所有文件,包括隐藏文件;-h 以人类可读的格式显示文件大小。

2、编写两个 bash 函数 marco 和 polo 执行下面的操作。 每当你执行 marco 时,当前的工作目录应当以某种形式保存,当执行 polo 时,无论现在处在什么目录下,都应当 cd 回到当时执行 marco 的目录。 为了方便 debug,你可以把代码写在单独的文件 marco.sh 中,并通过 source marco.sh 命令,(重新)加载函数。
答:

1
2
3
4
5
6
7
8
9
10
11
12
13
# marco.sh
# marco 函数:保存当前目录路径
marco() {
export SAVED_DIR="$(pwd)" # 使用 export 将变量导出,使得它可以被其他 shell 访问
}
# polo 函数:跳转回保存的目录
polo() {
if [ -z "$SAVED_DIR" ]; then # 检查 SAVED_DIR 是否为空,其中-z STRING:如果字符串STRING的长度为零(即为空字符串),则返回真(true),否则返回假(false)。
echo "Error: No directory saved. Please run 'marco' first."
else
cd "$SAVED_DIR" || echo "Error: Could not change to directory $SAVED_DIR"
fi
}

3、假设您有一个命令,它很少出错。因此为了在出错时能够对其进行调试,需要花费大量的时间重现错误并捕获输出。 编写一段 bash 脚本,运行如下的脚本直到它出错,将它的标准输出和标准错误流记录到文件,并在最后输出所有内容。
答:修改后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/env bash



# 初始化计数器

count=0

log_file="command_log.txt" # 定义一个变量 log_file ,用来存储日志文件路径



# 清空或创建日志文件

> "$log_file" # 将日志文件清空,如果文件不存在则创建。



while true; do

# 运行给定的命令,同时捕获标准输出和标准错误

n=$((RANDOM % 100)) # 生成一个 0 到 99 之间的随机数,并赋值给变量 n。

if [[ n -eq 42 ]]; then # 判断 n 是否等于 42,如果等于,则执行 then 后面的语句。

echo "Something went wrong" # 标准输出。在bash中如果不指定输出重定向,则echo默认标准输出,因此不需要显式指定>&1。

echo "The error was using magic numbers" >&2 # 标准错误输出

# 记录错误信息到日志文件

echo "执行失败,总共执行了 $count 次" >> "$log_file"

echo "最后一次执行的输出:" >> "$log_file"

echo "标准输出:Something went wrong" >> "$log_file"

echo "标准错误:The error was using magic numbers" >> "$log_file"

# 显示日志文件内容

cat "$log_file"

exit 1 # 退出脚本,并返回一个非零的退出状态,表示程序执行失败。从这里可以跳出while和do的循环。

fi

echo "Everything went according to plan"

((count++))

done

对于标准输出和标准错误输出,有如下例子:

1
2
# 将正确的信息输出到 output.txt,错误信息输出到 error.log
command > output.txt 2> error.log

4、您的任务是编写一个命令,它可以递归地查找文件夹中所有的 HTML 文件,并将它们压缩成 zip 文件。注意,即使文件名中包含空格,您的命令也应该能够正确执行。
答:find . -type f -name "*.html" -print0 | xargs -0 zip html_files.zip **使用 -print0xargs -0`:**

  • -print0 会让 find 输出的文件名之间用null 字符 (\0) 进行分隔,而不是空格或换行符。
  • xargs -0 会识别这些 null 字符,并将整个文件名(包括空格在内)作为一个单独的参数传递。

5、编写一个命令或脚本递归的查找文件夹中最近使用的文件。更通用的做法,你可以按照最近的使用时间列出文件吗?
答:`find /path -type f -printf “%T+ %p\n” | sort -r
其中

  • -printf "%T+ %p\n" 以 “+%Y-%m-%d %H:%M:%S” 格式输出文件的访问时间和路径。
  • sort -r 按时间戳逆序排序,最近访问的文件排在前面。

Shell Tools and Scripting
https://blakehansen130.github.io/2024/10/20/Shell Tools and Scripting/
发布于
2024年10月20日
许可协议