Nushell - CrossPlatform
在Bash中,可以通过 $OSTYPE
这个Bash Variable[1]判断系统信息:
case "$OSTYPE" in solaris*) echo "SOLARIS" ;; darwin*) echo "OSX" ;; linux*) echo "LINUX" ;; bsd*) echo "BSD" ;; msys*) echo "WINDOWS" ;; # via Git Bash/msysGit cygwin*) echo "ALSO WINDOWS" ;; # via Cygwin *) echo "unknown: $OSTYPE" ;;esac
其对Windows的判断有点麻烦;可以用 uname
程序代替,不过这就引入了新依赖。
Nushell作为相对现代的Shell,这点上做的便利一些,它在 $nu
[2] 常量里的 os-info
字段中记录了OS相关的信息,包括系统名称,架构 etc.
# 打印 $nu.os-info╭────────────────┬─────────╮│ name │ macos ││ arch │ aarch64 ││ family │ unix ││ kernel_version │ 25.1.0 │╰────────────────┴─────────╯
Demos
使用该字段作为条件,可以方便的编写跨平台函数/脚本,也方便针对不同平台编写对应的配置
Cross-Platform Functions/Scripts
不同系统的基础命令存在差异(如打开文件管理器),可以通过 match $nu.os-info.name
封装统一接口,屏蔽平台差异。
以打开文件管理器为例,Windows下要使用 explorer.exe
,而MacOS则为 Finder.app
;可以编写如下函数实现用平台默认的文件管理器打开指定文件夹
def omni-open [path: string = "."] { let path = ($path | path expand) match $nu.os-info.name { macos => { ^open $path } windows => { explorer.exe $path } linux => { ^xdg-open $path } # not tested }}alias o = omni-open
BTW,Nushell built-in的 start
命令其实实现了上面函数的功能,还支持打开URL,obsidian vault etc.
不同OS下剪贴板命令也不一样,macOS下使用 pbcopy
,Windows下使用 clip
;可以编写如下函数实现跨平台复制文本到剪贴板
def copy_text [] { match $nu.os-info.name { "windows" => { # Windows 使用 clip 命令 $in | ^clip } "macos" => { # macOS 使用 pbcopy 命令 $in | ^pbcopy } }}
使用场景:
# 复制当前路径pwd | copy_text# 复制某个文件的内容open README.md | copy_text
不同平台设置环境变量的方式也不一样,macos下使用 launchctl setenv
,windows下使用 setx
,linux的话可以将环境变量写入到 /etc/profile.d/**.sh
里,具体可以参考 Unix环境变量。这里可以编写一个Nushell funciton封装不同OS的差异
def --env env [name: string value: string] { # Set env var for current session load-env {$name: $value} match $nu.os-info.name { "macos" => { /bin/launchctl setenv $name $value } "linux" => { let env_file = "/etc/profile.d/gnix-env.sh" touch $env_file chmod +x $env_file let lines = (open $env_file | lines | where not ($it | str starts-with $"export ($name)=")) let env_value = ($value | str replace $nu.home-path "$HOME") let updated = ($lines | append $"export ($name)=\"($env_value)\"") $updated | str join (char nl) | save --force $env_file } "windows" => { setx $name $value } }}
OS-Specific Configs
Shell里配置文件通常会包含OS-specific的内容,比如Windows下的Scoop别名,macOS下的Homebrew补全脚本等,此外PATH
的设置也会因系统而异。
对于该问题,可以在 config.nu
里通过条件判断实现
Step 1: OS-specific Config
以 Windows 为例,创建platform/win.nu
存放专属配置
$env.YAZI_FILE_ONE = 'D:/envir_vars/scoop/apps/git/current/usr/bin/file.exe'source ../aliases/scoop.nusource ../completions/scoop.nusource ../completions/winget.nudef --env pwd [] { $env.PWD | str replace --all '\' '/'}alias su = scoop updatealias si = scoop installalias sui = scoop uninstallalias sse = scoop searchalias sst = scoop statusalias sl = scoop listalias sbl = scoop bucket listalias sba = scoop bucket addalias sbr = scoop bucket rmalias sui = scoop uninstallalias cdc = cd c://alias cdd = cd d://alias cde = cd e://
Step 2: Conditional Load
在 config.nu
里这样写,这里用到了Nushell里 source null
[3] 为no-op(no operation) 的feature
const window_module = if $nu.os-info.name == windows { "./platform/win.nu" } else { null }const mac_module = if $nu.os-info.name == macos { "./platform/mac.nu" } else { null }source $window_modulesource $mac_module
source | Nushell In Nushell, Sourcing
null
is a no-op. ↩︎
Nushell - CrossPlatform