uutils是一个用Rust重写的GNU Coreutils,也就是Linux上的cp
、mv
、touch
等程序的一个实现。虽然在Windows的PowerShell中执行这些命令也能得到类似于Linux的结果,但实际上是一个PowerShell内置cmdlet的alias,在某些情况下的兼容性并不是那么好。本文探索一种用uutils的命令替代PowerShell内置cmdlet的方法,以让Windows的命令行体验更加Unix化(虽然还是没那么Unix就是了)。
安装 uutils
可以使用预编译的二进制安装,也可以使用源代码编译安装。由于后面添加自动补全还需要源代码,所以我选择后者。
如果不需要shell自动补全,那么可以直接从上面GitHub仓库的releases下载对应的压缩包(coreutils-version-x86_64-pc-windows-{msvc|gnu}.zip),将解压后的coreutils.exe放在任何一个PATH下的目录下即可。至于如何添加PATH,此处不再赘述,很容易搜到。
默认编译或下载到的是multi-call binary,即调用方式为coreutils.exe <command>
,本文也按照这个情况书写。也可以编译为分离的二进制文件,具体请参考上面的GitHub Readme。
编译源代码需要先安装Rust工具链,未安装的请移步教程。
在你认为合适的位置,使用以下命令将其安装到Rust存放二进制文件的地方:
git clone https://github.com/uutils/coreutils
cd coreutils
cargo install --path . --features windows
编译出的二进制文件一般在%HomePath%/.cargo/bin里面,应该是默认添加到PATH的。安装完成后可以开一个新的PowerShell,运行coreutils
以验证是否安装完成。
为 PowerShell 添加自动补全
自动补全的主要用处大概是输入参数的时候能够按tab补全,如ls --di
按下tab可以补全为ls --directory
。
有点类似于Bash的.bashrc初始化脚本,PowerShell的自定义设置由profile管理。用户profile的路径内置于PowerShell的$profile环境变量,可以直接在PowerShell中运行notepad $profile
来编辑。
但自动补全文本量很大,可以将每个命令的补全各自写入一个文件,然后在profile中引用。对于把补全文件放在同一个文件夹内的情况,可以在profile中添加以下内容:
$completionsPath = "C:\path\to\completions" # Replace with the path to your completions directory
# Get all completion script files in the specified directory
$completionScripts = Get-ChildItem -Path $completionsPath -Filter "*.ps1" -File
# Load each completion script
foreach ($script in $completionScripts) {
. $script.FullName
}
这样就可以加载C:\path\to\completions(自己定义)里的补全预设了。
然后回到coreutils的源代码文件夹中,用PowerShell执行以下命令:
foreach($cmd in 'b2sum', 'b3sum', 'base32', 'base64', 'basename', 'basenc', 'cat', 'cksum', 'comm', 'cp', 'csplit', 'cut', 'date', 'dd', 'df', 'dir', 'dircolors', 'dirname', 'du', 'echo', 'env', 'expand', 'expr', 'factor', 'false', 'fmt', 'fold', 'hashsum', 'head', 'join', 'link', 'ln', 'ls', 'md5sum', 'mkdir', 'mktemp', 'more', 'mv', 'nl', 'numfmt', 'od', 'paste', 'pr', 'printenv', 'printf', 'ptx', 'pwd', 'readlink', 'realpath', 'relpath', 'rm', 'rmdir', 'seq', 'sha1sum', 'sha224sum', 'sha256sum', 'sha3-224sum', 'sha3-256sum', 'sha3-384sum', 'sha3-512sum', 'sha384sum', 'sha3sum', 'sha512sum', 'shake128sum', 'shake256sum', 'shred', 'shuf', 'sleep', 'sort', 'split', 'sum', 'tac', 'tail', 'tee', 'test', 'touch', 'tr', 'true', 'truncate', 'tsort', 'unexpand', 'uniq', 'unlink', 'vdir', 'wc', 'yes') {
cargo run completion $cmd powershell > "C:\path\to\completions\$cmd.ps1"
}
这样就可以把自动补全输出到你自定义的补全预设目录(还是别忘了替换路径)。
取代 PowerShell 自带 cmdlet alias
现在每次都要先输一个coreutils
命令才能调用,既不方便也没法用自动补全,干脆直接把命令映射过来。
直接Set-Alias
是不成功的,因为PowerShell自带alias。在profile中再添加以下内容:
foreach($cmd in 'b2sum', 'b3sum', 'base32', 'base64', 'basename', 'basenc', 'cat', 'cksum', 'comm', 'cp', 'csplit', 'cut', 'date', 'dd', 'df', 'dir', 'dircolors', 'dirname', 'du', 'echo', 'env', 'expand', 'expr', 'factor', 'false', 'fmt', 'fold', 'hashsum', 'head', 'join', 'link', 'ln', 'ls', 'md5sum', 'mkdir', 'mktemp', 'more', 'mv', 'nl', 'numfmt', 'od', 'paste', 'pr', 'printenv', 'printf', 'ptx', 'pwd', 'readlink', 'realpath', 'relpath', 'rm', 'rmdir', 'seq', 'sha1sum', 'sha224sum', 'sha256sum', 'sha3-224sum', 'sha3-256sum', 'sha3-384sum', 'sha3-512sum', 'sha384sum', 'sha3sum', 'sha512sum', 'shake128sum', 'shake256sum', 'shred', 'shuf', 'split', 'sum', 'tac', 'tail', 'test', 'touch', 'tr', 'true', 'truncate', 'tsort', 'unexpand', 'uniq', 'unlink', 'vdir', 'wc', 'yes') {
Remove-Alias $cmd -ErrorAction SilentlyContinue
Set-Item function:$cmd -Value { coreutils $cmd $args }.GetNewClosure()
}
(修改自这个Gist)
因为sleep
、tee
和sort
不允许修改,所以只好删掉了。
如果没有意外的话,再打开一个PowerShell,就可以使用新的 uutils了。
参考资料: