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 onrar
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
orif
/else
, but it's minimal impact. - Uses the first match found to mimic the behavior of
case
/if
/else
.