Home > Enterprise >  Cannot rewrite some function from bash to nushell
Cannot rewrite some function from bash to nushell

Time:11-27

I'm moving from bash to nushell. One of my steps was moving this function:

ex ()
{
  if [ -f $1 ] ; then
    case $1 in
      *.tar.bz2)   tar xjf $1   ;;
      *.tar.gz)    tar xzf $1   ;;
      *.bz2)       bunzip2 $1   ;;
      *.rar)       unrar x $1     ;;
      *.gz)        gunzip $1    ;;
      *.tar)       tar xf $1    ;;
      *.tbz2)      tar xjf $1   ;;
      *.tgz)       tar xzf $1   ;;
      *.zip)       unzip $1     ;;
      *.Z)         uncompress $1;;
      *.7z)        7z x $1      ;;
      *)           echo "'$1' cannot be extracted via ex()" ;;
    esac
  else
    echo "'$1' is not a valid file"
  fi
}

In nushell I wrote this:

def ex [$file?: string] {
        if $file == null {"No file defined"} else {
                if $file == *.tar.bz2 {
                        tar xjf $file;
                }
                else if $file == *.tar.gz {
                        tar xzf $file;
                }
                else if $file == *.bz2 {
                        bunzip2 $file;
                }
                else if $file == *.rar {
                        unzip $file;
                }
                else if $file == *.gz {
                        gunzip $file;
                }
                else if $file == *.tar {
                        tar xf $file;
                }
                else if $file == *.tbz2 {
                        tar xjf $file;
                }
                else if $file == *.tgz {
                        tar xzf $file;
                }
                else if $file == *.zip {
                        unzip $file;
                }
                else if $file == *.Z {
                        uncompress $file;
                }
                else if $file == *.7z {
                        7z x $file;
                }
        }
}

But when I tested it by this command(I had an openssl source code archive in a directory I was executing command from): ex openssl-1.1.1.tar.gz, I got this error: `

ex openssl-1.1.1.tar.gz                                                                                          
Error: nu::shell::external_command (link)

  × External command failed
     ╭─[/home/ysyltbya/.config/nushell/config.nu:523:1]
 523 │          }
 524 │          else if $file == *.tar.gz {
     ·   ──┬─
     ·     ╰── did you mean 'ls'?
 525 │                  tar xzf $file;
     ╰────
  help: No such file or directory (os error 2)

I can't understand what the problem is.

CodePudding user response:

The main issue is that you are still attempting to use the Bash patterns for string matching. You can accomplish this in Nushell with either:

  • The ends-with string comparison operator:

    if $file ends-with '.tbz2' ...
    
  • Or a regex comparison:

    if $file =~ '.*\.tbz2' ...
    

However, you might consider a more functional/data-driven/Nushell-way of doing it:

def ex [$file?: string] {
    let archivers = [
        [ pattern         , command              , options       ];
        [ ".tar.bz2"      , "tar"                , "xjf"         ]
        [ ".tar.gz"       , "tar"                , "xzf"         ]
        [ ".bz2"          , "unzip2"             , ""            ]
        [ ".tar.bz2"      , "tar"                , "xjf"         ]
        [ ".rar"          , "unrar"              , ""            ]
        [ ".gz"           , "gunzip"             , ""            ]
        [ ".tar"          , "tar"                , "xf"          ]
        [ ".tbz2"         , "tar"                , "xjf"         ]
        [ ".tgz"          , "tar"                , "xzf"         ]
        [ ".zip"          , "unzip"              , ""            ]
        [ ".Z"            , "uncompress"         , ""            ]
        [ ".7z"           , "7z"                 , "x"           ]
    ]

    if $file == null {
        print -e "No file defined"
    } else if not ($file | path exists) {
        print -e $"Can't find ($file)"
    } else {
        let matchingArchivers = ($archivers | where { |archiver| $file ends-with $archiver.pattern })
        if ($matchingArchivers | length) > 0 {
            let archiver = $matchingArchivers.0
            run-external $archiver.command $archiver.options $file
        } else {
            print -e $"($file) cannot be extracted via ex\(\)"
        }
    }
}

Notes:

  • Using this form, it's far easier to make changes and additions; more like the case of Bash in this sense.
  • I added in the other missing logic that you had like (a) checking that the file exists, and (b) checking that there was a matching app
  • Fixed the unzip command being used on rar files. Probably introduced some other transcription error in the process myself!
  • Yes, it does filter based on every possible match, rather than the normal "short-circuit" behavior of a case or if/else, but it's minimal impact.
  • Uses the first match found to mimic the behavior of case/if/else.
  • Related