Nushell - Cross-Platform
In Bash, you can detect the OS using the $OSTYPE 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
Detecting Windows is a bit cumbersome this way. You could use uname instead, but that introduces a new dependency.
Nushell, being a more modern shell, handles this more conveniently. It stores OS-related information — system name, architecture, etc. — in the os-info field of the $nu[2] constant:# Print $nu.os-info╭────────────────┬─────────╮│ name │ macos ││ arch │ aarch64 ││ family │ unix ││ kernel_version │ 25.1.0 │╰────────────────┴─────────╯
Demos
Using this field as a condition, you can easily write cross-platform functions/scripts and keep OS-specific configurations separate.
Cross-Platform Functions/Scripts
Basic commands differ across operating systems (e.g., opening the file manager). You can use match $nu.os-info.name to wrap a unified interface that hides platform differences.
Take opening the file manager: Windows uses explorer.exe, while macOS uses Finder.app. You can write a function that opens the specified folder with the platform’s default file manager:
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-openBy the way, Nushell’s built-in start command already does what the function above does, and also supports opening URLs, Obsidian vaults, etc.
Clipboard commands also differ across operating systems — pbcopy on macOS, clip on Windows. You can write a function to copy text cross-platform:
def copy_text [] { match $nu.os-info.name { "windows" => { # Windows uses the clip command $in | ^clip } "macos" => { # macOS uses the pbcopy command $in | ^pbcopy } }}Usage examples:
# Copy current pathpwd | copy_text# Copy a file's contentsopen README.md | copy_textEnvironment variable setup also varies by platform: launchctl setenv on macOS, setx on Windows, and writing to /etc/profile.d/**.sh on Linux. See [[Unix环境变量]] for details. You can write a Nushell function to encapsulate these differences:
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 config files often contain OS-specific content — Scoop aliases on Windows, Homebrew completion scripts on macOS, etc. PATH settings also vary by system.
You can handle this with conditional logic in config.nu:
Step 1: OS-specific Config
For Windows, create platform/win.nu to hold platform-specific config:$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
In config.nu, write it like this — using Nushell’s source null[3] feature as a no-op: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
nullis a no-op. ↩︎

