5

I have a lot of rar files

- Folder/
--- Spain.rar
--- Germany.rar
--- Italy.rar

All the files contains no root folder so it's just files.

What I want to achieve when extracting is this structure:

- Folder/
-- Spain/
---- Spain_file1.txt
---- Spain_file2.txt
-- Germany/
---- Germany_file1.txt
---- Germany_file2.txt
-- Italy/
---- Italy_file1.txt
---- Italy_file2.txt

So that a folder with the name of the archive is created and the archive is extracted to it.

I found this bash example in another thread but it's not working for me, it's trying to create one folder with all the files as name.

#!/bin/bash

for archive in "$(find . -name '*.rar')"; do
  destination="${archive%.rar}"
  if [ ! -d "$destination" ] ; then mkdir "$destination"; fi
  unrar e "$archive" "$destination"
done

Any ideas how I can do this?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175

3 Answers3

7

I have a script in my personal archive that does exactly this. More precisely, it extracts e.g. Spain.rar to a new directory called Spain, except that if all the files in Spain.rar are already under the same top-level directory, then this top-level directory is kept.

#!/bin/sh

# Extract the archive $1 to a directory $2 with the program $3. If the
# archive contains a single top-level directory, that directory
# becomes $2. Otherwise $2 contains all the files at the root of the
# archive.
extract () (
  set -e
  archive=$1
  case "$archive" in
    -) :;; # read from stdin
    /*) :;; # already an absolute path
    *) archive=$PWD/$archive;; # make absolute path
  esac
  target=$2
  program=$3
  if [ -e "$target" ]; then
    echo >&2 "Target $target already exists, aborting."
    return 3
  fi
  case "$target" in
    /*) parent=${target%/*};;
    */[!/]*) parent=$PWD/${target%/*};;
    *) parent=$PWD;;
  esac
  temp=$(TMPDIR="$parent" mktemp -d)
  (cd "$temp" && $program "$archive")
  root=
  for member in "$temp/"* "$temp/".*; do
    case "$member" in */.|*/..) continue;; esac
    if [ -n "$root" ] || ! [ -d "$member" ]; then
      root=$temp # There are multiple files or there is a non-directory
      break
    fi
    root="$member"
  done
  if [ -z "$root" ]; then
    # Empty archive
    root=$temp
  fi
  mv -v -- "$root" "$target"
  if [ "$root" != "$temp" ]; then
    rmdir "$temp"
  fi
)

# Extract the archive $1.
process () {
  dir=${1%.*}
  case "$1" in
    *.rar|*.RAR) program="unrar x";;
    *.tar|*.tgz|*.tbz2) program="tar -xf";;
    *.tar.gz|*.tar.bz2|*.tar.xz) program="tar -xf"; dir=${dir%.*};;
    *.zip|*.ZIP) program="unzip";;
    *) echo >&2 "$0: $1: unsupported archive type"; exit 4;;
  esac
  if [ -d "$dir" ]; then
    echo >&2 "$0: $dir: directory already exists"
    exit 1
  fi
  extract "$1" "$dir" "$program"
}

for x in "$@"; do
  process "$x"
done

Usage (after installing this script in your $PATH under the name extract and making it executable):

extract Folder/*.rar
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • This looks pretty awesome and I think this is what I need. But I am having trouble getting it to work. There seems to be something wrong with the way unrar is being called. When I run it, I get the usage example. It creates a lot of tmp folders but the extractions fails. What version of unrar did you use this on? – Dennis Wiencken Oct 19 '18 at 12:43
  • @DennisWiencken Evidently I'd never tried this version with anything but zip. Try my fixed version. – Gilles 'SO- stop being evil' Oct 19 '18 at 13:04
  • Works like a charm now! Thank you for the help! – Dennis Wiencken Oct 19 '18 at 13:40
3

You can use unar instead of unrar. It will default to creating a new directory of the same name when there is more than one rar file in the folder.

If there is only one file, you can use the -d option.

https://packages.ubuntu.com/search?keywords=unar

AdminBee
  • 21,637
  • 21
  • 47
  • 71
0
#!/bin/bash

# https://ostechnix.com/a-bash-function-to-extract-file-archives-of-various-types/
directory=`/usr/bin/dirname $1`
filename=`/usr/bin/basename $1`
filenameWithExt=$(/usr/bin/basename "$1")
filenameWithoutExt="${filenameWithExt%.*}"

# echo "directory: $directory"
# echo "filename: $filename"
# echo "filenameWithoutExt: $filenameWithoutExt"
# Bash Function To Extract File Archives Of Various Types
extract () {
    /usr/bin/mkdir "$directory/$filenameWithoutExt"
     if [ -f $1 ] ; then
         case $1 in
             *.tar.bz2)   /usr/bin/tar xjf "$1" -C "$directory/$filenameWithoutExt"     ;;
             *.tar.gz)    /usr/bin/tar xzf "$1" -C "$directory/$filenameWithoutExt"     ;;
             *.bz2)       /usr/bin/bunzip2 "$1" -C "$directory/$filenameWithoutExt"     ;;
             *.rar)       /usr/bin/rar x "$1" "$directory/$filenameWithoutExt"      ;;
             *.gz)        /usr/bin/gunzip "$1"      ;;
             *.tar)       /usr/bin/tar xf "$1" -C "$directory/$filenameWithoutExt"      ;;
             *.tbz2)      /usr/bin/tar xjf "$1" -C "$directory/$filenameWithoutExt"     ;;
             *.tgz)       /usr/bin/tar xzf "$1" -C "$directory/$filenameWithoutExt"    ;;
             *.zip)       /usr/bin/unzip "$1" -d "$directory/$filenameWithoutExt"       ;;
             *.Z)         /usr/bin/uncompress "$1"  ;;
             *.7z)        eval "7z e -o$directory/$filenameWithoutExt/ $1"  ;;
             *)           /usr/bin/echo "'$1' cannot be extracted via extract()" ;;
         esac
     else
         echo "'$1' is not a valid file"
     fi
}

extract "$1"