固有变量

  • $# 传给脚本的参数数量
  • $0 脚本的名称 (包括调用的指令路径)
  • $1 第一个参数
  • $@ 传递给 shell 脚本的所有参数, 作为一个整体
    • ${@:2} -> $2 $3 $4 …, 再拼成一个整体 (默认以空格连接)
  • $* 传递给 shell 脚本的所有参数, 作为一个字符串
    • ${*:2} -> $2 $3 $4 ..., 再拼成一个字符串 (默认以空格连接)
  • $$ 当前脚本运行的 PID
  • $? 上一个命令的退出状态, 0 表示成功, 非 0 表示失败

数组的定义

shell 中支持数组的定义, 语法如下

1
array_name=(value1 value2 value3 ...)

也就是在一系列通过常见分隔符(空格, 换行, 制表符) 分隔的值的括号中定义一个数组;

grep 等文本指令合作, 可以将文本文件的每一行读入到数组中, 也就是在外面加上一个 ($(grep 'pattern')) 就行 -> 这里的目的是通过 for 直接访问数组的每一个元素

同样的, 可以通过 @ 来访问数组的所有元素

1
2
3
for file in "${file_list[@]}"; do
...
done

Here-Document

here文档最通用的语法是 << 紧跟一个标识符, 从下一行开始是想要引用的文字, 然后再在单独的一行用相同的标识符关闭;
在Unix shell里, here文档通常用于给命令提供输入内容;

例如:

1
2
3
4
cat << EOF # 这里的 EOF 是标识符, 可以自定义为其他字符串
This is a here document.
It can contain multiple lines of text.
EOF

补救指令

类似于 c++catch 语句, || 可以在前一个命令失败时执行后一个命令;

1
cd ${HOME} || echo "Failed to change directory to HOME"

例如上述指令, 如果 cd ${HOME} 失败了, 就会输出 “Failed to change directory to HOME”;

同样的, 对于一个变量是否成功定义, 也可以用 {:-} 来进行补救

1
echo ${VAR:-"Default Value"}

如果 VAR 没有定义, 那么就会输出 “Default Value”;

${VAR:+word} 只有在 VAR 已设置且非空时才展开为 word

&& 语法

|| {} 语法相反, && 用于在前一个命令成功时执行后一个命令;

-eq== 语法的区别

一般的, -eq 用于整数比较, 而 == 用于字符串比较;

2>&1 指令的含义

这是一个输出的文件描述符, 其中

  • 0 代表标准输入 (stdin)
  • 1 代表标准输出 (stdout)
  • 2 代表标准错误输出 (stderr)
  • & 表示将标准错误输出重定向到标准输出

因此, 整个命令的含义是将标准错误输出重定向到标准输出, 这样所有的错误信息都会被发送到标准输出流中;

ssh 系列指令

ssh-keygen 密钥生成

从自动化脚本角度来考虑, 如果直接执行 ssh-keygen,
就会导致需要用户交互, 而且大多数人类都会直接输入空格, 那么这个交互其实应该跳过

如下指令就是可以直接创建一个新的 ssh 密钥对

1
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q
  • -t rsa 指定密钥类型为 RSA
    • 常见的加密算法是 rsaed25519
  • -f ~/.ssh/id_rsa 指定密钥文件的保存路径, 这里末尾不需要带 .pub, 因为 ssh-keygen 会自动生成公钥文件;
  • -N "" 指定密钥的密码, 这里是空字符串, 意味着不设置密码;
  • -q 表示安静模式, 不输出任何信息;
  • -C "comment" 表示的是在密钥中添加注释, 习惯上会写自己的邮箱地址, 因为有些网站会将 comment
    设置为文件标识符

ssh-agent 密钥管理器

ssh-agent 是一种控制用来保存公钥身份验证所使用的私钥的程序;

本质上 ssh-agent 就是一个密钥管理器, 运行 ssh-agent 以后, 使用 ssh-add 将私钥交给 ssh-agent 保管, 其他程序需要身份验证的时候可以将验证申请交给 ssh-agent 来完成整个认证过程;

1
2
ssh-add -l  # 列出当前 ssh-agent 中的密钥
ssh-add ~/.ssh/id_rsa # 将私钥添加到 ssh-agent 中

ssh options 选项

  • -t 强制分配伪终端(tty), 即使你的本地并不是交互式环境
    • 远程执行, 需要交互
  • -n 重定向标准输入到 /dev/null, 等同于在命令后面加 < /dev/null, 并阻止 ssh 从你的键盘读入;
    • 相当于在后台运行, 不占用标准输入

curl 指令

curl 指的是 client URL, 用于向指定 url 发送 web 服务器请求, 不带用任何参数的时候, 就是直接向对应 url 发送 GET 请求;

  • -A 参数指定 User-Agent, 默认的 UA 是 curl/[version]
    • curl -A '' https://google.com 就是不带 User-Agent 访问 google
  • -b 参数用来向服务器发送 cookie, 例如 curl -b 'foo=bar' https://google.com
    • cookie 的格式是 name=value 的形式, 可以使用多个 -b 参数来发送多个 cookie;
    • -b cookies.txt 用来读取本地的 cookies.txt 文件, 该文件的格式是 name=value 的形式, 每行一个 cookie;
  • -c 将服务器发回来的 cookie 写入一个文件
  • -d 参数用于发送 POST 请求
    • curl -d 'login=wesley&&password=123' -X POST https://google.com/login
  • --data-urlencode 发送 POST 请求, 但是会将发送的数据进行 url 编码
  • -e 参数用来设置 http 的表头 Referer 表示请求的来源
  • -F 参数用来向服务器上传二进制文件
  • -i 参数打印出服务器回应的 http 标头, -I 发出 HEAD 请求并且将返回的 http 标头打印出来
  • -L 参数会让 http 请求跟随服务器的重定向, 默认 curl 是不跟随重定向的
  • -o 参数把服务器的回应保存成文件, 等同于 wget 命令

/dev/null 的作用

/dev/null 属于字符特殊文件, 它属于空设备, 是一个特殊的设备文件, 它会丢弃一切写入其中的数据, 写入它的内容都会永远丢失, 而且没有任何可以读取的内容; 就像是黑洞一样

seq 指令

seq 指令用于生成一个数字序列, 其基本语法是 seq [options] [first [increment]] last 或者 seq [options] last;

option

  • -s 指定字符串分隔符, 默认是换行符
  • -w 在列前添加 0 使得宽度相同
  • -f 使用 printf 样式的浮点格式

示例

1
2
3
4
seq 1 10  # 生成从 1 到 10 的整数序列, 默认以换行符分隔
seq -s ',' 1 10 # 生成从 1 到 10 的整数序列, 用逗号分隔
seq -w 1 10 # 生成从 01 到 10 的整数序列, 宽度相同
seq -s ' ' 1 2 10 # 生成从 1 到 10 的奇数序列, 用空格分隔

注意 -f-w 不能同时使用, 因为 -f 会覆盖 -w 的效果;

管道 pipe 的使用原理

管道就是通过竖线"|"来连接多个命令, 以前面命令的输出作为后面一个命令的输入

用知乎上面非常常见的例子来说明

1
cat file.txt | sort | uniq

这个指令先用管道把 file.txt 展示出来之后将 stdout 传递给 stdin 即作为 sort 的输入, 然后 sort 会对输入的内容进行排序, 并将排序后的结果通过管道传递给 uniq, uniq 会过滤掉相邻的重复行, 最终输出唯一的行;

注意这里和 > 的重定向符号的区别, > 是将命令的输出重定向到一个文件中, 而管道是将一个命令的输出直接传递给另一个命令;

但是有一些指令本身不支持 stdin 输入参数, 只支持从 cli 中直接读取参数, 比如
rm, kill 等, 支持 stdin 的指令一般是处理文本的指令, 比如 cat, grep,
awk, sed, sort, uniq 等; 对于这些不支持的指令, 我们的解决方法是使用 xargs 指令;

tee io 输出重定向

和管道非常类似, tee 命令也可以将一个指令的输出和输入重定向

1
2
ls | tee file.txt  # 将 ls 的输出同时写入 file.txt 文件和标准输出 
ls | tee -a file.txt # 将 ls 的输出追加写入 file.txt 文件和标准输出

不仅如此, tee 指令支持 here doc 的写入, 用来格式化输入多行大量文本

1
2
3
4
tee file.txt << EOF
This is line 1
This is line 2
EOF

以及标准 > 重定向指令的权限问题, 因为 > 只作为一个终端内置操作符, 本身不能通过 sudo 来实现临时提权, 所有借助 tee 这个支持 sudo 的命令来实现

1
echo "New content" | sudo tee /etc/some_protected_file.conf

网络控制指令

nc netcat 指令

Linux nc命令用于设置路由器

1
ncc [options] [hostname] [port]

option 选项

  • -g <gateway> 指定源路由网关, 最多可以设置 8 个网关
  • -G <num> 指定源路由网关的数量
  • -h 显示帮助信息
  • -i <secs> 指定延迟时间, 以秒为单位
  • -l 监听模式, 用于接收传入的连接
  • -n 不进行 DNS 解析, 直接使用 IP 地址
  • -o <output_file> 将数据包以十六进制格式保存到指定文件
  • -p <port> 指定本地端口号
  • -r 随机选择端口号
  • -s <source_ip> 指定源 IP 地址
  • -u 使用 UDP 协议, 默认使用 TCP
  • -v 显示指令的详细输出
  • -w <secs> 指定等待连接的超时时间, 以秒为单位
  • -z 使用 0 io 模式, 只扫描监听端口, 不发送任何数据

example

1
nc -l -p 12345  # 在本地监听 12345 端口