news 2026/10/15 10:04:42

Cash 项目 sort 命令全解析:跨平台 ES6 实现的 Unix sort 排序工具实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cash 项目 sort 命令全解析:跨平台 ES6 实现的 Unix sort 排序工具实战指南
  • 开发工具
  • CLI

【免费下载链接】cash

Cross-platform Linux commands in ES6

项目地址:https://gitcode.com/gh_mirrors/ca/cash
点击查看免费下载

导读

本文围绕 Cash 项目中独立的cash-sort子包展开,系统讲解它如何以纯 ES6 在 Linux、Windows、macOS 上还原 Unixsort命令的核心能力。读完本文,你将掌握cash-sort的全局安装方式、全部命令行选项的语义与用法(数字排序、人类可读数字排序、月份排序、随机排序等)、管道与标准输入的处理机制,以及排序比较器的源码级实现原理和对应测试用例。

一、cash-sort 是什么:Cash 生态中的排序命令

cash-sort是 Cash 项目(仓库根目录 README.md 中描述为 "Cross-platform Linux commands in pure ES6")按命令拆分的独立 npm 子包。官方定位是:

This is a cross-platform, 100% ES6 implementation of the Unixsortcommand.

即:用纯 ES6 实现、不依赖原生编译的 Unixsort跨平台实现。它的package.json(packages/sort/package.json)中description为 "Cross-platform implementation of the Unix 'sort' command.",bin字段将sort绑定到./bin/sort.js,main指向./dist/commands/sort.js。

作为 Cash 项目的一部分,cash-sort与仓库中的cash-cat、cash-cp、cash-ls等同类子包遵循同一套构建流程:gulpfile.js中的packages任务会根据 commands.json 的配置,把dist目录下的命令实现、帮助文件、依赖工具和bin/parser.js一并打包进packages/sort/目录。需要说明的是,commands.json 的globalExclusions中包含sort,这意味着通过cash-global批量全局安装所有命令时,sort会被排除在外——这正是它拥有独立 npm 包、需要单独安装的原因之一。

二、安装与帮助:一条命令搞定全局可用

按照 packages/sort/README.md 的说明,全局安装cash-sort只需一条命令:

npm install cash-sort -g

安装完成后,sort会被注册到系统的全局 PATH 中,之后可以在任意目录直接调用。查看命令帮助:

> sort --help

--help输出内容由 src/help/sort.js 定义,完整帮助信息如下:

Usage: sort [OPTION]... [FILE]... Write sorted concatenation of all FILE(s) to standard output. Ordering options: -M, --month-sort compare (unknown) < 'JAN' < ... < 'DEC' -h, --human-numeric-sort compare human readable numbers (e.g., 2K 1G) -n, --numeric-sort compare according to string numerical value -R, --random-sort sort by random hash of keys -r, --reverse reverse the result of comparisons Other options: -c, --check, --check=diagnose-first check for sorted input; do not sort -o, --output=FILE write result to FILE instead of standard output --help display this help and exit With no FILE, or when FILE is -, read standard input.

除了全局安装为独立命令外,sort还能在 Cash 交互式 shell(运行cash后)中使用,也能以编程方式调用:require('cash')后可通过cash.sort(args, options)直接执行,这由 src/index.js 中基于vorpal.api的导出机制提供,与 test/sort.js 中cash.sort(dir, opts)的调用方式一致。

三、命令定义与选项总览

命令本身由 Vorpal 框架注册,定义位于 src/commands/sort.js:

vorpal .command('sort [files...]') .parse(preparser) .option('-M, --month-sort', 'compare (unknown) < \'JAN\' < ... < \'DEC\'') .option('-h, --human-numeric-sort', 'compare human readable numbers (e.g., 2K 1G)') .option('-n, --numeric-sort', 'compare according to string numerical value') .option('-R, --random-sort', 'sort by random hash of keys') .option('-r, --reverse', 'reverse the result of comparisons') .option('-c, --check', 'check for sorted input; do not sort') .option('-o, --output [file]', 'write result to file instead of standard output') .autocomplete(fsAutocomplete())

其中.parse(preparser)表示参数会先经过 src/preparser.js 预处理——把输入中的$VAR或${VAR}环境变量引用替换为process.env中的实际值(不存在时替换为空字符串),这一点在管道场景下尤为实用。

各选项的语义可汇总如下:

短选项长选项参数作用
-M--month-sort无按月名排序,未知 < JAN < ... < DEC
-h--human-numeric-sort无按人类可读数字排序(如 2K、1G)
-n--numeric-sort无按字符串的数值比较
-R--random-sort无按随机哈希打乱排序结果
-r--reverse无反转比较结果
-c--check无仅检查输入是否已排序,不排序
-o--outputFILE将结果写入文件而非标准输出

注意-o的参数是可选的([file]):源码中专门处理了"传了-o却没给文件名"的情况,此时会输出sort: option '--output' requires an argument并提示Try 'sort --help' for more information.,对应测试见 test/sort.js 的sort -o用例。

四、五种排序模式与比较器实现

排序的核心是 src/commands/sort.js 中传给Array.prototype.sort的比较函数。它对每一行分别提取aAlpha(去 ANSI 色码后保留字母数字字符)、aNumeric(仅保留数字字符),再按选项分派到不同模式。

4.1 默认字典序排序

无任何排序选项时,使用aAlpha.localeCompare(bAlpha)做字符串比较。这里先用 src/util/stripAnsi.js 去掉 ANSI 转义序列(这正是 Cash 生态的特色:输入可能来自其他命令的彩色输出),再剔除\W+非单词字符后比较,因此大小写混合、带符号的文本也能稳定排序。

来自 test/sort.js 的验证:对内容为zaz\nsss\nqqq\n-zbz\nBBB\nddd\nCCC\n2bbb\nccc\n的default.sort文件排序,期望输出为2bbb\nBBB\nccc\nCCC\nddd\nqqq\nsss\nzaz\n-zbz\n。

4.2 -n 数字排序

options.numericsort分支将两行的数字提取值相减:aNumeric - bNumeric,若数值相等则回退到aAlpha.localeCompare(bAlpha)保证稳定可比。注意提取方式是replace(/\D/g, ''),即取字符串中全部数字字符拼接后的数值,这解释了测试用例numeric.sort中22 zaz、77 ccc等行的排序结果:数字部分被提取后按数值大小排列,纯文本行(如CCC、-zbz)则按字典序排在数字行之前。

4.3 -h 人类可读数字排序

--human-numeric-sort对应 Unix coreutils 中sort -h的能力,用于处理2K、1G、2.5P这类带容量后缀的数字。源码中为此定义了排序组表(注释明确说明对齐 GNU coreutilssort.c的层级顺序):

const humanOrdering = {'': 0, 'K': 1, 'k': 1, 'M': 2, 'G': 3, 'T': 4, 'P': 5, 'E': 6, 'Z': 7}; const humanReadableSort = new RegExp(/^([0-9]+)?[\.]?[0-9]+[K|k|M|G|T|P|E|Z|Y]/g);

parseHumanReadableNumbers(nbr)的解析逻辑分两步:

  • 若匹配2K、1G、2.5P这类后缀数字格式,则拆出num(数值部分)和group(后缀对应组别);
  • 否则若以数字开头则提取parseFloat后的数值,非数字则返回-99999999999作为极小值垫底。

比较时先比group(即后缀的大小层级:K < M < G < T < P < E < Z),组别相同再比num,最终回退到字典序。测试用例human.sort的期望输出1k、8k、1M、5M、4G、3T、2.5P、2E、1Z完整覆盖了这一层级链。

4.4 -M 月份排序

--month-sort按月名排序。源码内置了月份序列表:

const monthOrdering = { jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6, jul: 7, aug: 8, sep: 9, oct: 10, nov: 11, dec: 12 }; const months = new RegExp(/^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i);

parseMonths(str)用不区分大小写的正则匹配行首的前三个字母,映射到 1~12 的月份序号;不匹配的返回 0(即"未知")。比较时若两个月序号相同(例如March与Marc都解析为 3),则回退到aAlpha.localeCompare(bAlpha)字典序。测试month.sort验证了4mar、56sevenjan、goats等非标准前缀行排在未知组,Marc/March/apr/APR等按月份序号排列的行为。

4.5 -R 随机排序

--random-sort在完成上述任一种排序后,使用依赖array-shuffle(Fisher-Yates 洗牌算法)对结果进行随机打乱:

if (options.randomsort) { parts = shuffle(parts); }

源码注释也坦言 "sorting arrays has woes"(数组随机排序的固有问题),并说明使用 Bostock 风格的 Fisher-Yates 实现。测试用例通过连续执行 100 次、断言结果不与上一次相同来验证随机性(每次 20 个元素的随机排列有 20! 种可能)。

4.6 -r 反转

--reverse在排序(或随机打乱)之后对parts整体执行parts.reverse(),即把结果数组反转而非修改比较器方向,因此它可以与上述任一排序模式叠加。测试用例同时验证了纯字典序反转、多文件合并反转以及-h与-r组合反转三种场景。

五、-c 检查与 -o 输出

5.1 -c 检查输入是否已排序

options.check分支不执行排序,而是逐行扫描判断输入是否乱序。检测规则与排序模式保持一致:当相邻两行都是数字时按parseFloat数值比较,否则按字符串a > b比较;一旦发现乱序,立即输出类似sort: -:6: disorder: e的诊断信息(-代表标准输入,6是乱序行的行号,e是乱序的那一行内容),并停止后续检查。对应测试:disorder.sort返回sort: -:6: disorder: e,disorder-numeric.sort返回sort: -:6: disorder: 26。源码注释指出,当前实现因多文件合并后丢失来源文件信息,暂不输出具体的文件名。

5.2 -o 写结果到文件

options.output分支将排序结果通过fs.writeFileSync写入指定文件而非标准输出。行为细节如下:

  • 目录不存在时返回sort: open failed: <file>: No such file or directory,退出码 2;
  • 其余写失败场景输出对应的错误码;
  • 正常写入时函数返回 0、不向标准输出打印任何内容。

测试用例验证了-o写出后可被cash.cat正确读回。

六、输入来源:文件、标准输入与管道缓冲

6.1 文件读取与错误处理

文件内容由 src/util/fetch.js 统一读取:它先调用 src/util/expand.js 对通配符(glob 模式)做展开,再逐个fs.readFileSync读取 UTF-8 文本;若目标是目录则返回sort: read failed: <name>: Is a directory,文件不存在则返回sort: cannot read: <name>: No such file or directory。多个文件会被拼接后统一排序,实现 "sorted concatenation of all FILE(s)" 的语义(见帮助文本),test/sort.js 中两次传入同一文件得到每行重复两份的期望输出即为验证。

6.2 标准输入与管道缓冲机制

不传文件参数时,sort读取标准输入(帮助文本说明 "With no FILE, or when FILE is -, read standard input")。由于sort必须等所有输入到齐才能排序,而管道传递 stdin 时数据可能被切分为多次回调,源码实现了一个 100ms 的缓冲机制:

if (args && args.stdin && options.bypass !== true) { sort.counter++; sort.stdin += `${args.stdin}\n`; if (sort.counter === 1) { setTimeout(function () { sort.counter = 0; args.stdin = sort.stdin; sort.stdin = ''; options.bypass = true; sort.exec.call(self, args, options); }, 100); } return; }

即:第一次收到 stdin 片段时启动 100ms 定时器,期间累积所有片段,到期后合并为完整输入再真正执行排序。这正是 Cash 中ipconfig | grep IPv4 | sort这类管道场景(见根 README.md 示例)能够正确工作的底层保障。

七、执行链路:interfacer 与三种调用形态

所有 Cash 命令都通过 src/util/interfacer.js 统一绑定执行:它把命令对象与调用方(Vorpal 交互式命令、cash.sort编程式调用)解耦,内部构造一个收集 stdout 的 logger,并把命令的返回值统一规整为回调结果。sort.exec因此只需聚焦"读入—排序—输出",无需关心自己是被 shell 还是被 Node API 调用。

bin/parser.js(由构建流程复制到每个子包的bin/目录)进一步决定了独立命令的执行路径:

  • 无参数时直接加载命令 JS 执行;
  • 带参数但无管道时,仅启动一个 Vorpal 实例加载sort单命令;
  • 出现|管道时则加载整个 Cash 库,让sort能与其他命令协作。

八、总结:何时选用 cash-sort

cash-sort适合以下场景:需要在 Windows 上获得与 Unix 一致的sort体验且不愿安装 Cygwin;想在 Node/JavaScript 环境中以编程方式调用排序(cash.sort());或希望只安装单个命令、保持系统 PATH 干净(而非通过cash-global一次性安装全部命令)。它的所有选项与行为均有对应测试用例(test/sort.js)和可阅读的源码(src/commands/sort.js、src/help/sort.js)支撑,属于 Cash 项目中文档、实现、测试三件套最完整的命令之一。使用前请确认 Node 版本满足engines要求(node >= 0.11.16/iojs >= 1.0.0,见 packages/sort/package.json),并注意其对 GNU coreutilssort选项的覆盖范围以 src/help/sort.js 列出的七项为准。

  • 开发工具
  • CLI

【免费下载链接】cash

Cross-platform Linux commands in ES6

项目地址:https://gitcode.com/gh_mirrors/ca/cash
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 10:04:39

微服务架构下的金融服务系统设计:账户、交易、风控与合规实践

1. 项目概述与核心需求拆解先说结论&#xff1a;这个名为 financial-services 的项目&#xff0c;表面上看是一个典型的金融服务中台抽象&#xff0c;实际上解决的是银行、保险、支付等机构在业务数字化过程中最头疼的"老系统带不动新业务"问题。我最早接手这类项目时…

作者头像 李华
网站建设 2026/10/15 10:04:36

Spring Boot与JDK版本兼容性问题解决方案

1. 问题现象与背景解析最近在搭建Spring Boot项目时遇到了一个典型的环境配置问题&#xff1a;启动时报错提示"Spring Framework版本与JDK版本不兼容"。这个错误看似简单&#xff0c;实则涉及Java生态中版本管理的核心机制。作为Java开发者&#xff0c;我们经常需要面…

作者头像 李华
网站建设 2026/10/15 10:04:35

知识图谱选型指南:从业务问题到数据模型与存储引擎的决策框架

企业级AI团队在做技术选型时&#xff0c;最容易被低估的一道题就是知识图谱。很多人觉得选型就是挑一个图数据库&#xff0c;Neo4j也好、JanusGraph也罢&#xff0c;装上就完事&#xff1b;但真正落地时才发现&#xff0c;知识图谱选型这道题&#xff0c;答的其实是"企业到…

作者头像 李华
网站建设 2026/10/15 10:04:11

信贷扩张时代已死,信用重组时代崛起

《信贷扩张时代已死&#xff0c;信用重组时代崛起》 ——钱没有消失&#xff0c;它只是换了一条路走贷款少借三万亿&#xff0c;存款多存二十万亿。这不是同一群人干的两件事&#xff0c;但所有人都把它读成了同一个故事。故事版本大致如此&#xff1a;老百姓不敢借钱&#xff…

作者头像 李华
网站建设 2026/10/15 10:03:47

MCP协议中context-mode的上下文感知原理与SQLite动态权重实现

1. “context-mode”不是功能开关&#xff0c;而是MCP协议中上下文感知能力的底层抽象最近在多个技术社区和项目文档里频繁看到“context-mode”这个词&#xff0c;尤其集中在与MCP协议、SQLite FTS5全文检索、本地AI工具链集成相关的讨论中。它既不像--verbose或--dry-run那样…

作者头像 李华