Untar
A simple script to extract compressed tar files.
#bash#go#tar#zip
BP
Bismit Panda
Created April 26th, 2025
go
package main
import (
"archive/tar"
"archive/zip"
"compress/bzip2"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/klauspost/compress/zstd"
"github.com/klauspost/pgzip"
"github.com/ulikunitz/xz"
"github.com/ulikunitz/xz/lzma"
)
var exts = map[string]string{
".tar": "tar",
".zip": "zip",
".gz": "gzip",
".tgz": "gzip",
".taz": "gzip",
".bz2": "bzip2",
".tz2": "bzip2",
".tbz2": "bzip2",
".tbz": "bzip2",
".xz": "xz",
".zst": "zstd",
".tzst": "zstd",
".lzma": "lzma",
".tlz": "lzma",
}
func extractArchive(filename, outdir string) error {
if err := os.MkdirAll(outdir, 0755); err != nil {
return err
}
ext := strings.ToLower(filepath.Ext(filename))
compress, ok := exts[ext]
if !ok {
return fmt.Errorf("unsupported extension: %s", ext)
}
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
if compress == "zip" {
return extractZip(file, outdir)
}
return extractTar(file, outdir, compress)
}
func sanitizePath(dst, target string) (string, error) {
target = filepath.Join(dst, target)
if !strings.HasPrefix(target, filepath.Clean(dst)+string(os.PathSeparator)) {
return "", fmt.Errorf("unsafe path: %s", target)
}
return target, nil
}
func extractZip(file *os.File, dst string) error {
stat, err := file.Stat()
if err != nil {
return err
}
r, err := zip.NewReader(file, stat.Size())
if err != nil {
return err
}
for _, header := range r.File {
target, err := sanitizePath(dst, header.Name)
if err != nil {
continue
}
if header.Mode().IsDir() {
os.MkdirAll(target, 0755)
} else {
os.MkdirAll(filepath.Dir(target), 0755)
src, err := header.Open()
if err != nil {
return err
}
outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, header.Mode())
if err != nil {
src.Close()
return err
}
_, err = io.Copy(outFile, src)
src.Close()
outFile.Close()
if err != nil {
return err
}
}
}
return nil
}
func extractTar(file *os.File, dst, compress string) error {
var reader io.Reader = file
switch compress {
case "gzip":
gr, err := pgzip.NewReader(file)
if err != nil {
return err
}
defer gr.Close()
reader = gr
case "bzip2":
reader = bzip2.NewReader(file)
case "xz":
xr, err := xz.NewReader(file)
if err != nil {
return err
}
reader = xr
case "lzma":
lr, err := lzma.NewReader(file)
if err != nil {
return err
}
reader = lr
case "zstd":
zr, err := zstd.NewReader(file)
if err != nil {
return err
}
defer zr.Close()
reader = zr
}
tarReader := tar.NewReader(reader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
target, err := sanitizePath(dst, header.Name)
if err != nil {
continue
}
switch header.Typeflag {
case tar.TypeDir:
os.MkdirAll(target, 0755)
case tar.TypeReg:
os.MkdirAll(filepath.Dir(target), 0755)
outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode))
if err != nil {
return err
}
_, err = io.Copy(outFile, tarReader)
outFile.Close()
if err != nil {
return err
}
}
}
return nil
}
bash
#!/bin/bash
extract_archive() {
local file="$1"
local outdir="$2"
if [[ -z "$file" || -z "$outdir" ]]; then
echo "Usage: extract_archive <archive_file> <output_directory>"
return 1
fi
if [[ ! -f "$file" ]]; then
echo "Error: File '$file' not found"
return 1
fi
mkdir -p "$outdir"
case "$file" in
*.tar.gz | *.tgz | *.tar.Z | *.taz)
echo "Detected gzip compression"
tar -xzf "$file" -C "$outdir"
;;
*.tar.bz2 | *.tbz2 | *.tbz | *.tar.bz | *.tz2)
echo "Detected bzip2 compression"
tar -xjf "$file" -C "$outdir"
;;
*.tar.xz | *.txz)
echo "Detected xz compression"
tar -xJf "$file" -C "$outdir"
;;
*.tar.zst | *.tzst)
echo "Detected zstd compression"
tar --zstd -xf "$file" -C "$outdir"
;;
*.tar.lzma | *.tlz)
echo "Detected lzma compression"
tar --lzma -xf "$file" -C "$outdir"
;;
*.tar)
echo "Detected tar compression"
tar -xf "$file" -C "$outdir"
;;
*.zip)
echo "Detected zip compression"
unzip -q "$file" -d "$outdir"
;;
*.gz)
echo "Detected gzip compression"
gunzip -c "$file" >"$outdir/$(basename "$file" .gz)"
;;
*.bz2)
echo "Detected bzip2 compression"
bunzip2 -c "$file" >"$outdir/$(basename "$file" .bz2)"
;;
*.xz)
echo "Detected xz compression"
xz -dc "$file" >"$outdir/$(basename "$file" .xz)"
;;
*.zst)
echo "Detected zstd compression"
zstd -dc "$file" >"$outdir/$(basename "$file" .zst)"
;;
*.lzma)
echo "Detected lzma compression"
lzma -dc "$file" >"$outdir/$(basename "$file" .lzma)"
;;
*)
echo "Error: Unsupported file format: $file"
return 1
;;
esac
if [[ $? -eq 0 ]]; then
echo "Successfully extracted '$file' to '$outdir'"
else
echo "Error: Failed to extract '$file'"
return 1
fi
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
extract_archive "$1" "$2"
fi
About the Author
BP
Bismit Panda
Full Stack Developer with 5+ years of experience. Passionate about React, TypeScript, and clean code.
View Profile