当前位置: 首页 > news >正文

Linux小课堂: 输入重定向与管道操作详解

控制命令的数据来源


在 Linux Shell 环境中,命令的执行不仅依赖于参数传递,更可通过输入重定向显式指定其数据源
标准输入(stdin)默认来自键盘,但通过特定符号可将其切换为文件内容或交互式键盘输入流
核心要点: 输入重定向(</<<)控制命令输入源,管道(|)实现命令间数据流转

输入重定向


1 ) 单小于号 <:从文件读取输入

使用单个 < 符号可将文件内容作为命令的标准输入。例如:

cat < notes.csv 

该命令与 cat notes.csv 的输出结果相同,但执行机制存在本质差异:

  • cat notes.csvcat 命令接收文件路径作为参数,自行打开并读取文件;
  • cat < notes.csv:Shell 先打开 notes.csv 文件,将其内容注入标准输入流,并将此流传递给 cat 命令;cat 仅负责读取 stdin 并输出。

重点:< 实现了输入源的解耦,使命令无需直接操作文件描述符即可处理外部数据。

2 )双小于号 <<:从键盘输入(Here Document)

双小于号 << 启用“Here Document”语法,允许用户通过键盘逐行输入文本,直到遇到指定的结束标识符为止。典型用法如下:

sort -n << END 
12
9 
27
END 

上述命令启动 sort -n(数值排序),随后进入交互模式。用户每输入一行数字并回车,系统即缓存该行。当输入 END 并再次回车后,Shell 将所有输入内容整体作为 sort -n 的标准输入进行处理,最终输出排序结果:

9 
12
27

技术细节:

  • 结束字符串(如 END)可自定义,大小写敏感
  • 输入过程中不可编辑历史行,需确保一次性正确输入
  • 若结束符前有空白字符(如 << EOF 后接空格),则必须严格匹配

此机制广泛用于脚本内嵌配置、临时数据生成等场景

管道操作符 |


管道是 Linux 命令行最强大的特性之一,它通过 | 符号将一个命令的输出(stdout)直接作为下一个命令的输入(stdin),形成级联处理链条

作用:将前一个命令的输出作为后一个命令的输入,实现多命令级联

1 ) 管道基本原理

command1 | command2 | command3

数据流动过程如下:

  • command1 执行,输出结果不显示在终端
  • 输出流被实时传递给 command2 作为输入
  • command2 处理完毕后,其输出继续传给 command3
  • 最终结果由最后一个命令输出到终端或重定向目标

性能优势:管道采用流式处理,无需中间文件暂存,极大提升效率

2 ) 基础应用(按学生名排序)

cut -d ',' -f1 notes.csv | sort > sorted_names.txt
  • cut 提取 CSV 第一列(学生名)→ sort 按字典序排序 → 结果重定向至文件。

3 ) 目录大小排序(前10名)

du | sort -nr | head
  • du 统计目录大小 → sort -nr 按数值倒序 → head 取前10行。

4 ) 关键词文件查找(系统日志)

sudo grep -Ir '/var/log' | cut -d: -f1 | sort | uniq 
  • grep 递归搜索 /var/log 含关键词的行 → cut 提取文件名 → sort 排序 → uniq 去重。

5 )示例一:提取并排序学生姓名

假设 notes.csv 文件格式如下:

Alice,88,Good job 
Bob,76,Average
Charlie,95,Excellent

目标:提取第一列(姓名),按字母顺序排序

cut -d',' -f1 notes.csv | sort 

分解说明:

  • cut -d',' -f1 notes.csv:以逗号分隔,提取第1字段(姓名);
  • | sort:将 cut 输出的姓名列表进行字典序排序。

结果:

Alice 
Bob
Charlie

进一步扩展,将结果保存到文件:

cut -d',' -f1 notes.csv | sort > sorted_names.txt

6 ) 示例二:按目录大小排序并取前10项

统计当前目录下各子目录磁盘占用,并按大小降序排列,取最大10个:

du -h | sort -hr | head -n 10 

各组件功能:

  • du -h:递归计算每个子目录总大小,人类可读单位(KB/MB/GB);
  • sort -hr
    • -h 支持对 K, M, G 单位进行智能排序;
    • -r 逆序输出,大值优先;
  • head -n 10:仅显示前10行结果。

注意:若 du 遇到权限不足目录会产生 stderr 错误信息,可能干扰排序。建议过滤非关键错误:

du -h 2>/dev/null | sort -hr | head -n 10

其中 2>/dev/null 抑制错误输出

7 ) 示例三:查找含关键字的唯一文件名

搜索 /var/log 目录中所有包含 log 字样的文本文件,并提取唯一的文件路径名:

grep -ri "log" /var/log | cut -d':' -f1 | sort | uniq

步骤详解:

  1. grep -ri "log" /var/log
    • -r:递归遍历 /var/log 子目录;
    • -i:忽略大小写匹配;
    • 输出格式为 文件路径:匹配行内容
  2. cut -d':' -f1:以冒号分割,提取第一部分(即文件路径);
  3. sort:对文件路径进行排序,为去重准备;
  4. uniq:去除相邻重复路径,保留唯一项。

补充技巧:若需统计各文件出现次数,可用:

grep -ri "log" /var/log | cut -d':' -f1 | sort | uniq -c | sort -nr 
  • uniq -c:前置计数;
  • sort -nr:数值逆序排列,高频文件排前。

输入与输出重定向结合:构建完整 I/O 控制链

输入重定向可与输出重定向及错误流控制组合使用,实现复杂的数据流向管理。

案例:排序键盘输入并保存至文件

sort -n << END > sorted_numbers.txt 2>&1
12
7
35 
END
  • << END 提供标准输入;
  • > sorted_numbers.txt 将标准输出重定向至文件;
  • 2>&1 表示将标准错误流合并至标准输出流,确保异常信息也写入同一文件。

运行后,sorted_numbers.txt 内容为:

7
12 
35

关键点:2>&1 必须置于其他重定向之后,否则无法正确绑定当前输出目标。

键盘输入数值 → sort 排序 → 结果与错误信息写入文件

构建自动化日志分析工具案例


1 ) 方案1

NestJS 命令执行模拟代码

import { Injectable } from '@nestjs/common';
import { exec } from 'child_process';
import { promisify } from 'util';const execAsync = promisify(exec);@Injectable()
export class CommandService {// 执行管道命令(目录大小排序)async sortDirectorySizes(): Promise<string> {const command = `du | sort -nr | head`;try {const { stdout } = await execAsync(command);return stdout;} catch (error) {throw new Error(`Command failed: ${error.stderr}`);}}// 输入重定向:从文件读取async readFromFile(filePath: string): Promise<string> {const command = `cat < ${filePath}`;const { stdout } = await execAsync(command);return stdout;}// 输入重定向:键盘输入模拟(TS实现)async keyboardInputSort(numbers: number[]): Promise<string> {const input = numbers.join('\n') + '\nEND';const command = `sort -n << END\n${input}\nEND`;const { stdout } = await execAsync(command);return stdout.trim();}
}

代码说明:

  • sortDirectorySizes:模拟 du | sort -nr | head,返回目录大小排序结果
  • readFromFile:使用 < 重定向读取文件内容
  • keyboardInputSort:动态生成 << 输入重定向命令,对数值数组排序

2 )方案2

模拟日志关键词提取与聚合逻辑

日志分析服务代码

// log-analysis.service.ts
import { Injectable } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';interface LogMatch {filePath: string;lineNumber: number;content: string;
}@Injectable()
export class LogAnalysisService {/* 模拟 grep -ri 功能:递归查找关键词 */async searchKeywordInLogs(rootDir: string, keyword: string): Promise<LogMatch[]> {const results: LogMatch[] = [];const scan = async (dir: string) => {const entries = await fs.promises.readdir(dir, { withFileTypes: true });for (const entry of entries) {const fullPath = path.join(dir, entry.name);if (entry.isDirectory()) {if (!['.', '..'].includes(entry.name)) await scan(fullPath);} else if (entry.isFile() && this.isTextFile(entry.name)) {await this.searchInFile(fullPath, keyword, results);}}};await scan(rootDir);return results;}private isTextFile(filename: string): boolean {const ext = path.extname(filename).toLowerCase();return ['.log', '.txt', '.csv', ''].includes(ext); // 简化判断}private async searchInFile(filePath: string,keyword: string,results: LogMatch[],) {try {const data = await fs.promises.readFile(filePath, 'utf-8');const lines = data.split(/\r?\n/);const lowerKeyword = keyword.toLowerCase();lines.forEach((line, index) => {if (line.toLowerCase().includes(lowerKeyword)) {results.push({filePath,lineNumber: index + 1,content: line.trim(),});}});} catch (err) {console.warn(`无法读取文件: ${filePath}`, err.message);}}/* 提取唯一文件路径(类比 cut | sort | uniq)*/extractUniqueFilePaths(matches: LogMatch[]): string[] {return [...new Set(matches.map(m => m.filePath))].sort();}/* 统计每个文件命中次数(类比 uniq -c)*/countPerFile(matches: LogMatch[]): Array<{ filePath: string; count: number }> {const map = new Map<string, number>();matches.forEach(m => map.set(m.filePath, (map.get(m.filePath) || 0) + 1));return Array.from(map.entries()).map(([filePath, count]) => ({ filePath, count })).sort((a, b) => b.count - a.count);}
}

控制器调用示例

// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { LogAnalysisService } from './log-analysis.service';@Controller('logs')
export class AppController {constructor(private readonly logService: LogAnalysisService) {}@Get('search/:keyword')async search(@Param('keyword') keyword: string) {const matches = await this.logService.searchKeywordInLogs('/var/log', keyword);const uniqueFiles = this.logService.extractUniqueFilePaths(matches);const topFiles = this.logService.countPerFile(matches).slice(0, 10);return {totalMatches: matches.length,uniqueFilesCount: uniqueFiles.length,top10FilesByHits: topFiles,sampleMatches: matches.slice(0, 5),};}
}

对应 Shell 命令映射关系

Shell 命令NestJS 实现
grep -ri "log" /var/logsearchKeywordInLogs()
cut -d':' -f1matches.map(m => m.filePath)
sort.sort()
uniq[...new Set(...)]
uniq -c | sort -nrcountPerFile().sort((a,b)=>b-a)

设计思想:NestJS 服务封装了 Shell 管道的逻辑流本质——数据变换链(Data Transformation Pipeline),体现了函数式编程与 Unix 设计哲学的高度融合

技术细节总结


符号作用数据流向
<文件→命令文件内容作为命令输入
<<键盘→命令逐行输入至结束字符串
|命令A→命令B前命令输出作为后命令输入
> / >>命令→文件输出覆盖/追加到文件

关键原则:

  1. 管道符 | 级联命令时,每个命令的输出必须为文本流
  2. 输入重定向(</<<)替代参数输入,直接提供数据源。
  3. 组合使用(如 << END > file)可实现 交互式输入+输出存储

核心要点凝练

特性符号作用典型应用场景
输入重定向(文件)<将文件内容作为命令输入cat < file.txt
Here Document<<接收键盘输入直至结束符脚本中嵌入多行配置
管道``将前命令输出作为后命令输入
输出重定向> / >>控制命令输出位置结果持久化
错误合并2>&1统一处理 stdout 与 stderr日志记录完整性

终极原则:
一切皆流(Everything is a stream) —— Linux 的强大源于对“流”的极致抽象。无论是文件、键盘、网络还是进程间通信,统一通过 stdin/stdout 接口进行交互,而重定向与管道正是操控这些数据流的核心手段

http://www.dtcms.com/a/506954.html

相关文章:

  • AI+BI工具全景指南:重构企业数据决策效能
  • 全球云服务震荡:Amazon Web Services (AWS) 出现大规模故障 多项线上服务受冲击
  • 3.Rocky Linux 磁盘管理
  • led行业网站源码asp网站浏览器兼容
  • Linux基本指令(3)
  • TypeScript 快速入门与环境搭建
  • Python数据分析实战:基于PISA 2022金融素养数据集,解构“借衣服收2元”背后的青少年金钱观【数据集可下载】
  • 用TikZ绘制专业流程图:从入门到进阶(基于D3QN训练流程)
  • Java 反射机制实战:对象属性复制与私有方法调用全解析
  • 火星时代UE奶瓜粒子特效②
  • 网站制作流程图wordpress 维文版
  • MySQL与K8s:数据库运维新范式
  • 第9篇 opencv提取矩形角度不是很准确的处理方法
  • 检测十字标 opencv python
  • NSSCTF - Web | 【SWPUCTF 2021 新生赛】Do_you_know_http
  • Linux小课堂: 流、重定向与 cut 命令进阶
  • 虚拟内存核心常识
  • ubuntu配置mysql8.0并设置Navicat网络连接
  • 深圳网站维护一般多少钱网址大全黄免费片
  • 从若依框架看权限设计与数据字典:背后的工程化思考
  • 邦策网站建设平台网站建设文化咨询
  • ASTM D7033-2022 定向刨花板检测
  • 使用ThreadLocal的一些注意事项
  • Kotion 常见用法注意事项(持续更新...)
  • 如何使用思维导图提升信息整理效率
  • K-VXE-TABLE二次封装,含table‘自定义列功能
  • 基于 GEE 开发的一种利用 OTSU 算法实现水体提取的便捷工具
  • Linux小课堂: 深入解析 top、htop、glances 及进程终止机制
  • 建设协会网站洛阳伟创科技
  • MongoDB 提供的 `GridFSTemplate` 操作 GridFS 大文件系统的常用查询方式