Linux 命令行进阶:重定向、管道、变量与任务控制

2026-10-9 / 0 评论 / 2 阅读

Linux 命令行进阶:重定向、管道、变量与任务控制 原创示意图

会用 cd、ls 和 cat 之后,下一步不是背更多命令,而是学会把命令组合起来。Linux 命令行的力量主要来自输入输出重定向(Redirection)、管道(Pipe)、变量(Variable)和退出状态(Exit status)。下面所有实验都可以在家目录中的临时文件夹完成。

mkdir -p ~/cli-lab
cd ~/cli-lab
printf 'nginx\nssh\nmysql\nssh\n' > services.txt

一、标准输入、标准输出和错误

程序通常有三条数据通道:标准输入(Standard input,stdin,编号 0)、标准输出(Standard output,stdout,编号 1)和标准错误(Standard error,stderr,编号 2)。正常结果走 stdout,报错走 stderr,所以它们可以分别处理。

sort services.txt > sorted.txt
sort services.txt >> history.txt
ls /not-exist 2> error.log

> 创建或覆盖文件;>> 追加;2> 只保存错误。要把正常输出和错误都放进一个日志,可写:

some-command > all.log 2>&1

2>&1 的意思是让编号 2 跟随编号 1 当前指向的位置。顺序会影响结果,新手使用时最好保留上面的固定写法。

二、用管道把小命令拼起来

竖线 | 会把左边命令的输出交给右边作为输入:

sort services.txt | uniq -c
ps aux | grep ssh
ip address | less

第一条先排序,再统计相邻重复行;第二条在进程列表中搜索 ssh;第三条把较长的网卡信息交给分页器(Pager)。如果只想匹配真正的进程而不看到 grep 自己,可使用 pgrep -a ssh。

过滤日志时经常组合 grep、tail 和 less:

journalctl -u ssh --no-pager | tail -n 30
grep -n 'ssh' services.txt

-n 在匹配结果前显示行号。不要随意把未知输出管给会修改系统的命令,先用 less 检查数据再决定下一步。

三、;、&& 和 || 不一样

command1 ; command2
command1 && command2
command1 || command2

分号表示无论第一条成功与否都执行第二条;&& 只在第一条成功时继续;|| 只在第一条失败时继续。例如:

sudo apt update && sudo apt upgrade
test -f /etc/ssh/sshd_config && echo 'SSH 配置存在'

每个程序结束时都会返回一个数字,0 通常表示成功,非 0 表示失败。刚执行完命令后,可用 echo $? 查看退出状态。

四、变量、引号和展开

创建变量时等号两边不能有空格:

SERVER_NAME='lab-server'
echo "$SERVER_NAME"
echo "当前用户是 ${USER},主机是 $(hostname)"

$变量名 是变量展开(Variable expansion);$(命令) 是命令替换(Command substitution)。双引号(Double quotes)允许变量和命令展开,单引号(Single quotes)把内容原样保留:

echo "$HOME"
echo '$HOME'

第一条会显示家目录,第二条只显示字符 $HOME。处理包含空格的路径时始终加双引号,例如 cp "$SOURCE_FILE" "$TARGET_DIR/"。

PATH 是非常重要的环境变量(Environment variable):

echo "$PATH"
command -v nginx

Shell 会依次在 PATH 列出的目录中寻找程序。不要为了运行一个不明脚本随便把当前目录加入系统级 PATH。

五、后台任务和进程

在命令末尾加 & 可放到后台(Background)运行:

sleep 60 &
jobs

jobs 显示当前 Shell 的任务;fg %1 把 1 号任务带回前台;前台程序按 Ctrl+Z 是暂停,不是退出,再用 bg %1 可让它在后台继续。查看系统进程可用 ps aux,实时观察可用 top。终止进程时先尝试普通 kill 进程号,不要一开始就用强制信号 kill -9。

通过 SSH 执行长期任务时,关闭连接可能使任务结束。更可靠的方法是使用 tmux、screen 或 systemd 服务,而不是只在命令后加 &。

六、一个实用的系统报告

{
  echo '=== 时间 ==='
  date
  echo '=== 运行时间 ==='
  uptime
  echo '=== 磁盘 ==='
  df -h
} > system-report.txt

花括号把多条命令分组(Command grouping),统一重定向到文件。执行 less system-report.txt 检查结果。这种“小命令组合”正是以后写 Shell 脚本、做自动备份和定时巡检的基础。

七、通配符与查找命令

Shell 会在程序运行前展开通配符:* 匹配任意长度字符,? 匹配一个字符,[0-9] 匹配一个数字。例如:

printf '%s\n' *.txt

先用 printf 或 ls 预览匹配结果,再把同样的模式用于复制或移动。尤其不要未经预览就把通配符交给 rm。

find 可以按名称、类型和时间筛选:

find ~/cli-lab -type f -name '*.txt'
find /var/log -type f -mtime -1 2>/dev/null | head

第二条寻找一天内修改过的日志文件。这里先用管道交给 head 查看,不直接对结果执行删除。网络文章中常见的 find ... -exec rm 风险很高,必须先去掉删除部分检查完整列表。

八、理解权限失败,而不是一律 sudo

命令失败时先看错误属于哪一类:command not found 通常是程序未安装或不在 PATH;No such file or directory 多半是路径错误;Permission denied 才可能涉及权限。检查文件和父目录:

ls -ld .
ls -l 文件名
namei -l /完整/路径/文件名

只有确认操作本来就需要管理员权限时才使用 sudo。不要用 sudo chmod -R 777 解决权限问题,它会把所有人都授予读写执行权限,还可能破坏程序对敏感文件的安全检查。应当先判断文件属于哪个用户和组,再只调整真正需要的一项权限。

九、把复杂命令拆开验证

看到一条包含多个管道、重定向和 sudo 的长命令时,先在测试目录中逐段运行。确认每一段的输入和输出,再组合;涉及变量时先用 printf '%q\n' "$变量" 检查值;涉及下载脚本时先保存并阅读,不要直接使用 curl ... | sh。命令行越灵活,越需要把“可验证”放在“少敲几次键”之前。

十、tee、子 Shell 与当前目录

有时既想在屏幕看到输出,又想保存到文件,可用 tee:

ip -br address | tee network-report.txt
journalctl -u ssh -n 20 | sudo tee /tmp/ssh-report.txt >/dev/null

第二条里的 sudo 只给 tee,因此它能写入需要权限的位置。sudo command > /受保护/文件 常常失败,因为重定向是当前 Shell 在 sudo 之前完成的。

圆括号会启动子 Shell(Subshell),其中的目录和临时变量不会影响外层:

pwd
(cd /tmp && pwd)
pwd

花括号分组则通常在当前 Shell 运行,命令之间需要用换行或分号分隔。写自动化命令时,先判断你是否希望 cd、变量等状态在后续继续生效,再选择括号形式。

还要注意管道中各命令一般各自运行,某一段失败不一定让整条管道显眼地失败。写正式 Shell 脚本时可研究 set -o pipefail,让管道中任意环节失败都返回非零状态;在交互终端中则应逐段检查输出。

本文为中文学习整理,重点概念和实验顺序经过重新编排。资料来源:Ubuntu Server 官方文档:The command line in depth。

评论一下?

OωO
取消