Nushell is a newish, MIT-licensed, Free Open Source Software (FOSS) command shell, an alternative to shells such as bash and fish and zsh. Unlike those shells that treat data as text, Nushell (or just nu) treats data like database data. It's kind of like a cross between text-based shells like the ones just mentioned and the strongly-object-oriented Powershell on Windows (the next generation of Powershell, version 7, is also available on Debian; this version is named pwsh to help make the distinction that it's essentially a different, but work-a-like, product than the Powershell 5 on your Windows boxes.)
As of 31 October 2025 (Happy Halloween!), the way to install nu on Debian (or Ubuntu) is:
curl -fsSL https://apt.fury.io/nushell/gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/fury-nushell.gpg
echo "deb https://apt.fury.io/nushell/ /" | sudo tee /etc/apt/sources.list.d/fury.list
sudo apt update
sudo apt install nushell
Just paste that code into a terminal and it should ask for your sudo password, download Nushell as a .deb installer file, and install it.
If much time has passed since this page was created, or you need instructions for other operating systems, you'd do well to visit the Nushell website.
Be aware that Nushell is a young product, and the language is evolving rapidly, so that what works today may not work tomorrow. Much of the references you'll find on places like Reddit or on Artificial Intelligence (AI) sites may be out of date. The Nushell site and its discussion group on GitHub are your best bet for accurate, up-to-date information.
#!/usr/bin/env nu
# Printer name must be provided on command-line.
@example "" {
./get-printer-ip.nu adm214_mfp
}
@example "" {
./get-printer-ip.nu "my printer"
}
def main [ printer: string ] { # Looking for a string, like "ADM214_MFP"
## 1) Set the Configuration ---
# Set the server name.
let server = '\\print.acu.edu'
# Set the name of the credentials file
let creds_file = ".config/private/acu_creds"
# ---------------------
## 2) Get the credentials
# Check if the credentials file exists
let creds = if ($creds_file | path exists) == false {
# --- Credentials file does not exist ---
print $"\nCredentials file does not exist at \"($creds_file)\"."
print "The file must contain a username and password that has"
print $"access to connect to \"($server)\", and must be in"
print "the format:\n"
print "username = <value>"
print "password = <value>"
print "domain = <value>"
print ""
print "(The domain may be optional, depending on your Windows environment.)"
print ""
print "Please make sure this file is not readable by unauthorized persons."
print ""
# Prompt the user for credentials
print $"Press Ctrl-C to stop this program, or ..."
print ""
print $"Please enter credentials for ($server):"
let user_input = (input "Username: ")
let pass_input = (input "Password: " -s)
# Format the content for the 'rpcclient -A' file
let new_creds_content = $"username = ($user_input)\npassword = ($pass_input)\n"
# --- Save the credentials ---
print "" # Move past the password-input line
let save_choice = (input "Save these credentials for future use? (y/n): ")
if ($save_choice | str starts-with "y" -i) {
# Save the raw string content to the file
$new_creds_content | save $creds_file
# CRITICAL: Secure the new file
chmod 600 $creds_file
print $"Credentials saved in \"($creds_file)\" for next time."
}
}
# ---------------------
## 3) Run rpcclient
let ip_address = (
try {
# This is the command that tries to find the specific printer.
rpcclient -A $creds_file -c $"getprinter \"($printer)\" 5" $server
} catch {
# If the 'try' block fails...
# 1. Print a header message.
print "Here's a list of available printers:"
# 2. Get the raw text of *all* printers from the server.
let printers = (rpcclient -A $creds_file $server -c "enumprinters")
# 3. Print a formatted list.
print ($printers
| lines # Break the multi-line string into individual lines.
| where {|line| $line =~ "name:"} # Find only lines with "name:"
| str trim # Remove whitespace
| parse 'name:[{value}]' # Get the value from inside name:[...]
| get value # Select just that value (e.g., \\SERVER\PRINTER)
| each { |it| # Split each line to get the name
$it | split row '\\' | split row '\' | last
}
)
# 4. Print the final error messages.
print $"\"($printer)\" is not available on the server \"($server)\"."
print "The above is a list of available printers."
# 5. Exit the script successfully (since we did what was asked).
exit 0
}
)
# ---------------------
## 4) If the 'try' above did work, print the result.
# The result of a succesful 'try' (in '$ipaddress') should look something like this:
# printername:[\\PRINT.ACU.EDU\ZEL300_MFP]
# portname:[10.66.1.5]
# attributes:[0x2a48]
# device_not_selected_timeout:[0xafc8]
# transmission_retry_timeout:[0xafc8]
print ($ip_address
# Trim whitespace from whole multi-line string.
| str trim
# Break that into individual lines to make a table.
| lines
# The output now looks like:
# ╭───┬──────────────────────────────────────────╮
# │ 0 │ printername:[\\PRINT.ACU.EDU\ZEL300_MFP] │
# │ 1 │ portname:[10.66.1.5] │
# │ 2 │ attributes:[0x2a48] │
# │ 3 │ device_not_selected_timeout:[0xafc8] │
# │ 4 │ transmission_retry_timeout:[0xafc8] │
# ╰───┴──────────────────────────────────────────╯
# Find only the lines containing "name".
| where {|line| $line =~ "name:"}
# Looks like this now:
# ╭───┬──────────────────────────────────────────╮
# │ 0 │ printername:[\\PRINT.ACU.EDU\ZEL300_MFP] │
# │ 1 │ portname:[10.66.1.5] │
# ╰───┴──────────────────────────────────────────╯
# Break up the line at the ":[...]" into two columns named "name" and "value".
| parse '{name}:[{value}]'
# Looks like this:
# ╭───┬─────────────┬────────────────────────────╮
# │ │ name │ value │
# ├───┼─────────────┼────────────────────────────┤
# │ 0 │ printername │ \\PRINT.ACU.EDU\ZEL300_MFP │
# │ 1 │ portname │ 10.66.1.5 │
# ╰───┴─────────────┴────────────────────────────╯
# In each cell, trim whitespace.
| update cells { str trim }
# Swap rows/columns; use resulting 1st row as headers.
| transpose -r
# "transpose" by itself results in:
# ╭───┬─────────┬────────────────────────────┬───────────╮
# │ # │ column0 │ column1 │ column2 │
# ├───┼─────────┼────────────────────────────┼───────────┤
# │ 0 │ name │ printername │ portname │
# │ 1 │ value │ \\PRINT.ACU.EDU\ZEL300_MFP │ 10.66.1.5 │
# ╰───┴─────────┴────────────────────────────┴───────────╯
# but "transpose -r" results in:
# ╭───┬────────────────────────────┬───────────╮
# │ # │ printername │ portname │
# ├───┼────────────────────────────┼───────────┤
# │ 0 │ \\PRINT.ACU.EDU\ZEL300_MFP │ 10.66.1.5 │
# ╰───┴────────────────────────────┴───────────╯
# Select and rename the "printername" and "portname" columns.
| select printername portname
| rename -c {printername : "Printer Name", portname : "IP Address"}
# Don't show the index-number column.
| table --index false
# Result should look like:
# ╭────────────────────────────┬────────────╮
# │ Printername │ IP Address │
# ├────────────────────────────┼────────────┤
# │ \\PRINT.ACU.EDU\ZEL300_MFP │ 10.66.1.5 │
# ╰────────────────────────────┴────────────╯
)
}