A command-line shell like fish, but POSIX compatible.

Overview

nsh

CI Status Latest version

A command-line shell that focuses on productivity and swiftness featuring:

  • A POSIX compliant interactive shell with some Bash extensions.
  • Tab completions and syntax highlighting.
  • Bash completion support (by internally invoking the genuine Bash).
  • Builtin zero configration features.
  • Written in Rust 🦀

screenshot

Installation

$ cargo install nsh

Documentation

Documentation

Why create a new shell?

Bash is the best for executing shell scripts but its interactive mode is not satisfactory. I am a zsh user for the last decade but I don't need customizability and got tired of making my zshrc faster. Fish is really neat but I prefer old-fashioned, traditional, and ergonomic shell syntax.

Contributing

nsh is in alpha stage: there are many missing features which Bash provides, there are kludges in source code, and there must be bugs. To make nsh practical for daily use, I need your help!

How can I contribute?

  • Report bugs in GitHub issues. Please attach a minimal reproducible example (e.g. shell script) if possible. It helps me to fix the bug easier.
  • Suggest enhancements in GitHub issues.
  • Submit a Pull Request which implements a new feature, fixes a bug, refactors code, rephrases sentences in documentation, etc.

License

CC0 or MIT. Choose whichever you prefer.

Comments
  • nsh fails to build

    nsh fails to build

    Hi,

    As I saw some updates, I tried to build nsh on two machines, with same ending, building fails :

       Compiling textwrap v0.11.0
       Compiling heck v0.3.1
       Compiling proc-macro-error-attr v0.4.11
       Compiling proc-macro-error v0.4.11
       Compiling pest_meta v2.1.3
       Compiling quote v1.0.3
       Compiling atty v0.2.14
       Compiling signal-hook-registry v1.2.0
       Compiling dirs v1.0.5
       Compiling termion v1.5.5
       Compiling rand_core v0.5.1
       Compiling clap v2.33.0
       Compiling signal-hook v0.1.13
       Compiling rand_chacha v0.2.1
       Compiling rand_pcg v0.2.1
       Compiling rand v0.7.3
       Compiling syn-mid v0.5.0
       Compiling synstructure v0.12.3
       Compiling pest_generator v2.1.2
       Compiling phf_generator v0.8.0
       Compiling backtrace-sys v0.1.33
       Compiling backtrace v0.3.45
       Compiling proc-macro-hack v0.5.11
       Compiling pest_derive v2.1.0
    error[E0433]: failed to resolve: could not find `__rt` in `quote`
       --> /home/rsalle/.cargo/registry/src/github.com-1ecc6299db9ec823/failure_derive-0.1.6/src/lib.rs:107:70
        |
    107 | fn display_body(s: &synstructure::Structure) -> Result<Option<quote::__rt::TokenStream>, Error> {
        |                                                                      ^^^^ could not find `__rt` in `quote`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0433`.
    error: could not compile `failure_derive`.
    warning: build failed, waiting for other jobs to finish...
    error: failed to compile `nsh v0.3.0`, intermediate artifacts can be found at `/tmp/cargo-installwDSerl`
    
    Caused by:
      build failed
    

    and rustc --explain E0433 gives :

    An undeclared type or module was used.
    
    Erroneous code example:
    
    let map = HashMap::new();
    // error: failed to resolve: use of undeclared type or module `HashMap`
    
    Please verify you didn't misspell the type/module's name or that you didn't
    forget to import it:
    
    use std::collections::HashMap; // HashMap has been imported.
    let map: HashMap<u32, u32> = HashMap::new(); // So it can be used!
    

    Thanks

    opened by rapha8l 6
  • Cannot compile on FreeBSD 13.0

    Cannot compile on FreeBSD 13.0

    • Architecture: 64-bit x86
    • OS: FreeBSD 13.0
    • rustc: 1.53.0

    When compiling via cargo install --path ., I get the following:

       Compiling nsh v0.4.0 (/usr/home/kts/Develop/nsh)
    warning: use of deprecated associated function `nix::errno::<impl nix::errno::Errno>::Sys`: Use Errno::... instead
       --> src/process.rs:319:13
        |
    319 |         Err(nix::Error::Sys(nix::errno::Errno::ECHILD)) | Ok(WaitStatus::StillAlive) => {
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
        = note: `#[warn(deprecated)]` on by default
    
    error[E0164]: expected tuple struct or tuple variant, found associated function `nix::Error::Sys`
       --> src/process.rs:319:13
        |
    319 |         Err(nix::Error::Sys(nix::errno::Errno::ECHILD)) | Ok(WaitStatus::StillAlive) => {
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
        |
        = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
    
    warning: use of deprecated associated function `nix::errno::<impl nix::errno::Errno>::Sys`: Use Errno::... instead
       --> src/process.rs:475:21
        |
    475 |                 Err(nix::Error::Sys(nix::errno::Errno::EACCES)) => {
        |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    error[E0164]: expected tuple struct or tuple variant, found associated function `nix::Error::Sys`
       --> src/process.rs:475:21
        |
    475 |                 Err(nix::Error::Sys(nix::errno::Errno::EACCES)) => {
        |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
        |
        = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
    
    error: aborting due to 2 previous errors; 2 warnings emitted
    
    

    I would fix this myself but I do not know Rust nor its ecosystem (and as such, don't know if it is an expected Rust version mismatch or otherwise).

    opened by kettek 5
  • fix #44

    fix #44

    fixes #44

    The lib update of the nix package to 0.25 brought removed the argument in the gethostname function.

    This lead to:

    error[E0061]: this function takes 0 arguments but 1 argument was supplied
        --> .../.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/prompt.rs:131:25
         |
    131  |     let hostname_cstr = unistd::gethostname(&mut hostname_buf).expect("failed to get hostname");
         |                         ^^^^^^^^^^^^^^^^^^^ ----------------- argument unexpected
         |
    note: function defined here
        --> .../.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.25.0/src/unistd.rs:1020:8
         |
    1020 | pub fn gethostname() -> Result<OsString> {
         |        ^^^^^^^^^^^
    help: remove the extra argument
         |
    131  |     let hostname_cstr = unistd::gethostname().expect("failed to get hostname");
         |                         ~~~~~~~~~~~~~~~~~~~~~
    
    For more information about this error, try `rustc --explain E0061`.
    error: could not compile `nsh` due to previous error
    error: failed to compile `nsh v0.4.2`, intermediate artifacts can be found at `/var/folders/dt/97jrrt3s3yn7z7bgr3rv0wy40000gn/T/cargo-installHlVCo7`
    
    opened by VuiMuich 2
  • Missing POSIX (?) syntax

    Missing POSIX (?) syntax

    Running Homebrew's shellenv script (necessary to use packages installed via Homebrew) by running

    eval "$(/opt/homebrew/bin/brew shellenv)"
    

    results in an error:

    nsh: parse error:  --> 4:56
      |
    4 | export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}";␊
      |                                                        ^---
      |
      = expected param_op
    

    Which corresponds to line 48 in the aforementioned script.

    Is this POSIX-compliant syntax? If so, an implementation for this seems to be missing.

    opened by ghost 2
  • Multibyte (and/or double width) character problem

    Multibyte (and/or double width) character problem

    I was trying out nsh on my macbook and encountered this. (might be related to #14 ?)

    [ERROR	] /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/main.rs: panicked at 'called `Result::unwrap()` on an `Err` value: RecvError', /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/bash_server.rs:26:33
    [ERROR	] /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/main.rs: panicked at 'index out of bounds: the len is 20 but the index is 53', /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/mainloop.rs:1153:13
    [ERROR	] /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/main.rs:    0:        0x102083c18 - backtrace::capture::Backtrace::new::hba9adf1e5b3c7a91
       1:        0x10204a7d8 - nsh::main::{{closure}}::h67739294c6afee12
       2:        0x1020ffe9d - std::panicking::rust_panic_with_hook::hae2b05f08a320721
       3:        0x10211dc5c - std::panicking::begin_panic_handler::{{closure}}::h72d68d3a77e0b718
       4:        0x10211dc27 - std::sys_common::backtrace::__rust_end_short_backtrace::h7c5e286792f94edb
       5:        0x10211dbe0 - _rust_begin_unwind
       6:        0x102136d9f - core::panicking::panic_fmt::h1b194bb80d76fb10
       7:        0x102136d66 - core::panicking::panic_bounds_check::hde7f7e34704d5da2
       8:        0x102016118 - nsh::mainloop::Mainloop::handle_key_event::h72f2fc3ed6d69a71
       9:        0x1020119ae - nsh::mainloop::Mainloop::handle_event::h98f98893dfe246aa
      10:        0x10200e02f - nsh::mainloop::Mainloop::run::hd7a071cbdcd9cbdc
      11:        0x1020466e2 - nsh::shell_main::ha315b12f85f157a9
      12:        0x102049ff9 - nsh::main::h367ea8887b771698
      13:        0x101fa32aa - std::sys_common::backtrace::__rust_begin_short_backtrace::hde4e21082195018a
      14:        0x102060794 - _main
    
    [ERROR	] /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/main.rs: panicked at 'called `Result::unwrap()` on an `Err` value: RecvError', /Users/$USER/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/bash_server.rs:26:33
    

    I'm in a LANG=ja_JP.UTF-8 environment, and nsh was acting weird in a directory with a name consisting multibyte letters. (The left prompt and the actual input area were separated way apart) The actual crash occurred when trying to type a letter after completing a multibyte directory name.

    PoC:

    nsh
    $ mkdir ぴーおーしー
    $ cd <TAB> <select ぴーおーしー> <return> <type any letter>
    

    (sidenote: ぴーおーしー is "PoC" in Japanese hiragana representation and doesn't mean anything)

    bug 
    opened by yu-ichiro 2
  • This (simple) PR makes it possible to BackTab (shift+tab) while in completion mode.

    This (simple) PR makes it possible to BackTab (shift+tab) while in completion mode.

    Hi.

    While tabbing my way through completions, I was unable to shift back (back tab) as I'm used to. This PR adds the keybinding shift+tab in completion_mode.

    As I understand it, the guard 'if self.completion_mode()' is repeated for both patterns, but I might be wrong. I have very little experience with Rust and low-level languages in general. I glanced the manual regarding match expression, but I found it a bit confusing, so I'm hoping you can confirm that this PR causes no side effects.

    opened by xanderificnl 2
  • nsh fails to compile

    nsh fails to compile

    rustc 1.48.0 (7eac88abb 2020-11-16) Linux lptp 5.9.11-arch2-1 #1 SMP PREEMPT Sat, 28 Nov 2020 02:07:22 +0000 x86_64 GNU/Linux

    I get this error while compiling nsh:

    error[E0277]: `&SignalsInfo` is not an iterator
       --> src/mainloop.rs:137:27
        |
    137 |             for signal in &signals {
        |                           ^^^^^^^^ `&SignalsInfo` is not an iterator
        |
        = help: the trait `Iterator` is not implemented for `&SignalsInfo`
        = note: required by `into_iter`
    
    opened by GoldsteinE 2
  • config files in $XDG_CONFIG_HOME

    config files in $XDG_CONFIG_HOME

    Hi

    Thanks for your shell, I'm just beginning to test ! I was wondering if you could use $XDG_CONFIG_HOME like ~/.config/nsh instead of .nshrc Thanks ! Raphaël

    opened by rapha8l 2
  • Multibyte character problem fix

    Multibyte character problem fix

    Fixes #34

    This fixes the crash, but there still are problems with the display of the cursor. A refactor using something like unicode-segmentation would probably fix the problems, since it allows handling graphemes instead of chars.

    opened by thomasqueirozb 1
  • implement (naive) `exec` builtin command

    implement (naive) `exec` builtin command

    This P-R partially implements exec command. It only supports exec cat maggie syntax and doesn't exec 3< readfile.

    See also https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#exec

    opened by KeenS 1
  • Fix pattern matching when already sitting in the directory that is defined with absolute value in the searched pattern

    Fix pattern matching when already sitting in the directory that is defined with absolute value in the searched pattern

    When located in the directory (e.g. /etc) then absolute location pattern matching for that single directory doesn't work as expected. Example:

    Located in home directory (works fine):

    in_home

    vs located in /etc (/etc is expected to be in the results, but is not):

    in_etc

    opened by svekko 1
  • error when compiling nsh using cargo install

    error when compiling nsh using cargo install

     Compiling nsh v0.4.2
    error[E0061]: this function takes 0 arguments but 1 argument was supplied
        --> /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/prompt.rs:131:25
         |
    131  |     let hostname_cstr = unistd::gethostname(&mut hostname_buf).expect("failed to get hostname");
         |                         ^^^^^^^^^^^^^^^^^^^ ----------------- argument of type `&mut [u8; 128]` unexpected
         |
    note: function defined here
        --> /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.26.1/src/unistd.rs:1020:8
         |
    1020 | pub fn gethostname() -> Result<OsString> {
         |        ^^^^^^^^^^^
    help: remove the extra argument
         |
    131  |     let hostname_cstr = unistd::gethostname().expect("failed to get hostname");
         |
    
    opened by clemdemort 1
  • Crash on EOF

    Crash on EOF

    I'm in the habit of inserting the EOF character with ctrl+d to quit command-line programs. If I do that in nsh, I get the follwoing error:

    nsh: panicked at 'called `Result::unwrap()` on an `Err` value: RecvError', /home/eliminmax/.local/lib/rust/cargo/registry/src/github.com-1ecc6299db9ec823/nsh-0.4.2/src/bash_server.rs:26:33
    nsh:    0:     0x55cbf52482a7 - <unknown>
       1:     0x55cbf5237d95 - <unknown>
       2:     0x55cbf51dd51e - <unknown>
       3:     0x55cbf52cf904 - <unknown>
       4:     0x55cbf52cf5b7 - <unknown>
       5:     0x55cbf52cd324 - <unknown>
    
    opened by eliminmax 0
  • Function color check

    Function color check

    Nsh already checks if aliases exist and highlights them with a green color accordingly. The same thing doesn't work for functions though.

    alias l="ls -la"
    

    works, while

    l () {
        ls -la
    }
    

    doesn't.

    opened by ghost 0
  • Aliases not evaluated

    Aliases not evaluated "procedurally"

    In ZSH (and I believe other shells as well) something like the following is possible (example):

    alias ls="exa"
    alias l="ls -la"
    

    which will both execute exa since the first alias remaps the default unix ls to exa.

    In Nsh, this doesn't work. The second alias runs the default ls instead.

    What would be the scope of this change? What would need to be done?

    bug 
    opened by ghost 0
  • Rewrite (almost) everything

    Rewrite (almost) everything

    IIRC, this shell is implemented as my first step in Rust long long ago, and it has some faults:

    • A monolithic single crate: takes too much time even in an incremental build.
    • Async is not used: just because async Rust was still in the alpha stage then.
    • Mainloop is fat

    This issue aims to deal with these problems by rewriting nsh when I have time (hopefully Q1 2022).

    opened by nuta 1
  • several POSIX-compliance issues

    several POSIX-compliance issues

    • variable assignments where the value to be assigned is an empty string don't work, such as
      foo=
      
    • redirections can't be applied to brace groups (and perhaps other compound commands):
      { :; } >&2
      
    • the last case item in a case list has to be terminated explicitly, otherwise it won't work:
      case x in
      x) foo
      esac
      
    • case items where the pattern is enclosed in a pair of parens don't work either:
      case x in
      (x) foo ;;
      esac
      
    • pattern matching parameter expansions don't work at all:
      foo=bar
      echo ${foo#}
      
    • when invoked with -c, the shell doesn't accept positional parameters:
      nsh -c '' nsh 1 2 3
      

    I didn't test any further than this.

    bug 
    opened by oguz-ismail 1
Owner
Seiya Nuta
Seiya Nuta
A super simple prompt for Fish shell, just shows git info and Vi mode.

vifi is a portmandeau of 'Vi' and 'Fish', because it's a prompt for Fish shell, primarily focused around showing proper indicators when using Vi key bindings.

Mat Jones 1 Sep 15, 2022
Nvm - Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions

Node Version Manager Table of Contents Intro About Installing and Updating Install & Update Script Additional Notes Troubleshooting on Linux Troublesh

nvm.sh 63.8k Jan 7, 2023
A bit like tee, a bit like script, but all with a fake tty. Lets you remote control and watch a process

teetty teetty is a wrapper binary to execute a command in a pty while providing remote control facilities. This allows logging the stdout of a process

Armin Ronacher 259 Jan 3, 2023
Application microframework with command-line option parsing, configuration, error handling, logging, and shell interactions

Abscissa is a microframework for building Rust applications (either CLI tools or network/web services), aiming to provide a large number of features w

iqlusion 524 Dec 26, 2022
A command line interface meant to bridge the gap between Rust and shell scripting

clawbang A command line interface meant to bridge the gap between Rust and shell scripting. Intended for use with HEREDOCs and shebangs: $ clawbang <<

Chris Dickinson 52 Mar 25, 2022
Non-interactive nREPL client for shell scripts and command-line

nreplops-tool (nr) nreplops-tool (nr) is a non-interactive nREPL client designed to be used in shell scripts and on the command-line. Early α warning:

Matti Hänninen 3 Jul 1, 2022
A command-line tool for patching shell scripts inspired by resholve

patsh A command-line tool for patching shell scripts inspired by resholve nix run github:nix-community/patsh -- -f script.sh Usage Usage: patsh [OPTIO

Nix community projects 23 Jan 7, 2023
Fish with bombs.

Fish Folk: Bomby Fish with bombs. This game is part of the Fish Folk bundle! Take a look at some of the other games being worked on: Jumpy Punchy Foll

Fish Folk 19 Dec 27, 2022
Nushell "extern" definitions for tab completion generated from Fish's

Nushell completions pack This is a system for generating extern defs (tab-completion) in nu. Background The fish shell project has a long, complicated

Scott Boggs 7 Feb 28, 2023
Gone Fish - A Rust Game

Gone Fish A game created for GitHub Game Off 23 - Scale. Fish, upgrade, repeat. Catch fish to upgrade your equipment, and catch the biggest fish you c

null 6 Dec 1, 2023
Small command-line tool to switch monitor inputs from command line

swmon Small command-line tool to switch monitor inputs from command line Installation git clone https://github.com/cr1901/swmon cargo install --path .

William D. Jones 5 Aug 20, 2022
A system clipboard command line tools which inspired by pbcopy & pbpaste but better to use.

rclip A command line tool which supports copy a file contents to the system clipboard or copy the contents of the system clipboard to a file. Install

yahaa 3 May 30, 2022
Safe Unix shell-like parameter expansion/variable substitution via cross-platform CLI or Rust API

Safe Unix shell-like parameter expansion/variable substitution for those who need a more powerful alternative to envsubst but don't want to resort to

Isak Wertwein 4 Oct 4, 2022
Low-level Rust library for implementing terminal command line interface, like in embedded systems.

Terminal CLI Need to build an interactive command prompt, with commands, properties and with full autocomplete? This is for you. Example, output only

HashMismatch 47 Nov 25, 2022
A simple command line tool for creating font palettes for engines like libtcod

palscii A simple command line tool for creating font palettes for engines like libtcod. Usage This can also be viewed by running palscii --help. palsc

Steve Troetti 2 May 2, 2022
dog is a command-line DNS client, like dig

dog dog is a command-line DNS client. Dogs can look up! dog is a command-line DNS client, like dig. It has colourful output, understands normal comman

Benjamin Sago 4.8k Jan 8, 2023
rpsc is a *nix command line tool to quickly search for file systems items matching varied criterions like permissions, extended attributes and much more.

rpsc rpsc is a *nix command line tool to quickly search for file systems items matching varied criterions like permissions, extended attributes and mu

null 3 Dec 15, 2022
🍬 shell-candy is a library that wraps Rust's `std::process::Command`

?? shell-candy is a library that wraps Rust's `std::process::Command`, providing a functional mechanism for handling stdout/stderr streams of spawned tasks..

Avery Harnish 6 Oct 25, 2022
Command-line HTTP client for sending a POST request to specified URI on each stdin line.

line2httppost Simple tool to read lines from stdin and post each line as separate POST request to a specified URL (TCP connection is reused though). G

Vitaly Shukela 3 Jan 3, 2023