“2>/dev/null”是一个常见的 Shell 重定向(Redirection) 基础语法,表示遇到错误直接丢弃。一个使用场景:
# macOS Keychain 里删除指定的(MY_SERVICE_NAME,MY_ACCOUNT_NAME)密码记录 # 加了 2>/dev/null 后,表示即使没找到这个记录,也别报错 security delete-generic-password -s "MY_SERVICE_NAME" -a "MY_ACCOUNT_NAME" 2>/dev/null下面解释下 “2>/dev/nul” 各段含义。
1.“2”代表「标准错误流」
Unix/Linux 系统默认给每个程序打开3个标准数据流管道,它们各自有一个固定的编号(文件描述符):
| 编号 | 名称 | 缩写 | 默认去向 | 作用 |
|---|---|---|---|---|
| 0 | 标准输入 | stdin | 键盘 | 接收用户输入 |
| 1 | 标准输出 | stdout | 屏幕 | 打印正常结果 |
| 2 | 标准错误 | stderr | 屏幕 | 打印报错信息 |
重点:正常输出和错误是完全独立的两个管道,不会互相干扰。比如你执行一个不存在的命令
abc,弹出的「命令不存在」提示,就是走的2号错误管道。
2.“>”是「重定向符号」
>的作用是:把左边管道的输出,写到右边指定的地方,而不是默认输出到屏幕。
- 你平常写
echo "hello" > a.txt,其实是echo "hello" 1> a.txt的简写(1可以省略),意思是把正常输出写到a.txt文件里。 - 要重定向错误流,就必须明确指定管道编号:
2> xxx,意思是把错误信息写到xxx里。
1> file.txt 或 > file.txt:Shell 会把 1(标准输出) 重定向到文件,1是默认值,可以省略。
2> file.txt:就是告诉 Shell 只把编号为 2 的“标准错误”重定向到文件,正常的输出依然打印在屏幕上。
3.“/dev/null”是「黑洞设备」
/dev/null是 Unix/Linux 系统中的一个特殊的虚拟设备文件。它的特性极其简单粗暴:
- 写入它的数据会被立刻丢弃,不占用任何存储空间。
- 从它读取数据会永远返回空。
可以把它想象成一个无底洞或垃圾桶,无论往里扔多少东西都会瞬间消失。
4. 组合 “2>/dev/null”
把上面三部分拼在一起,逻辑就非常清晰了:
2>/dev/null: 把“标准错误(2)”这个数据流,重定向到“黑洞(/dev/null)”里。
结果就是:命令执行过程中产生的所有报错信息都被扔进了黑洞,终端屏幕上干干净净,什么都不会显示。
举例:当执行一个不存在的命令:
# 不加2>/dev/null:会打印错误到屏幕 $ abc zsh: command not found: abc # 加2>/dev/null:错误直接丢弃,屏幕啥也不输出 $ abc 2>/dev/null5. 回到开头的例子
# macOS Keychain 里删除指定的(MY_SERVICE_NAME,MY_ACCOUNT_NAME)密码记录 security delete-generic-password -s "MY_SERVICE_NAME" -a "MY_ACCOUNT_NAME" 2>/dev/nullsecurity delete命令里加这个参数的目的就是:
如果钥匙串里本来就没有要删除的记录,
security命令会报「找不到条目」的错误,但我们不关心这个错误(本来就是要删,不存在就不用删),所以直接把错误丢掉,避免脚本输出冗余的报错信息。
security是macOS 内置的钥匙串(Keychain)命令行工具。macOS 会把密码、证书等敏感信息加密存在钥匙串里。security是官方命令行接口,几个常见子命令:
| 子命令 | 作用 |
|---|---|
add-generic-password | 添加一条密码 |
find-generic-password | 查找一条密码 |
delete-generic-password | 删除一条密码 |
解析:security delete-generic-password -s "MY_SERVICE_NAME" -a "MY_ACCOUNT_NAME" 2>/dev/null | |
|---|---|
| 部分 | 含义 |
security | macOS 钥匙串的 CLI 工具(内置) |
delete-generic-password | 子命令:删除一条通用密码(generic password)。 |
-s "MY_SERVICE_NAME" | -s= service,服务的标识。相当于"这条密码属于哪个服务" |
-a "MY_ACCOUNT_NAME" | -a= account,账户名。用来区分同一服务下不同用户 |
2>/dev/null | 把标准错误丢弃。忽略命令报错信息 |
Keychain 里每条记录由 (service, account) 这对组合唯一定位,相当于数据库的主键。