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?

up vote 5 down vote accepted

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
  • 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 at 12:43
  • @DennisWiencken Evidently I'd never tried this version with anything but zip. Try my fixed version. – Gilles Oct 19 at 13:04
  • Works like a charm now! Thank you for the help! – Dennis Wiencken Oct 19 at 13:40

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.