Extracting cpio Archives to a Specific Directory in GNU/Linux (RHEL 4) – Avoiding Directory Changes in Scripts


2 views

When working with cpio archives in RHEL 4 or GNU/Linux systems, a common frustration arises when trying to extract files directly to a specific directory without changing the current working directory. The default behavior forces you to either:


# The clunky way we want to avoid
cd /target/directory
cpio -idv < archive.cpio
cd -

You can actually specify the target directory directly in the cpio command using the --no-absolute-filenames option combined with path specification:


cpio --extract --make-directories --no-absolute-filenames --directory=/target/path < archive.cpio

Or in its shorter form:


cpio -id -D /target/path < archive.cpio

This approach provides several advantages:

  • Maintains script cleanliness by avoiding directory changes
  • Prevents potential issues if the cd command fails
  • Makes the extraction destination explicit in the command
  • Works better in complex scripts with error handling

Here's how you might implement this in a robust shell script:


#!/bin/bash

ARCHIVE="/path/to/archive.cpio"
TARGET_DIR="/custom/installation/path"

if [ ! -d "$TARGET_DIR" ]; then
    mkdir -p "$TARGET_DIR" || exit 1
fi

if [ -f "$ARCHIVE" ]; then
    cpio -id -D "$TARGET_DIR" < "$ARCHIVE" || {
        echo "Extraction failed" >&2
        exit 1
    }
else
    echo "Archive file not found" >&2
    exit 1
fi

Note that some older versions of cpio might require slightly different syntax. For maximum compatibility across systems:


(cd /target/path && cpio -id) < archive.cpio

This uses a subshell to contain the directory change, preventing the need to return to the original directory.

When extracting to a different directory, you might want to preserve the original file permissions:


cpio -idum -D /target/path < archive.cpio

The -m option maintains original file modification times, while -u unconditionally overwrites existing files.


Many sysadmins working with legacy RHEL 4 systems encounter this pain point: cpio stubbornly extracts files relative to the current working directory, forcing messy directory navigation in scripts. While cd workarounds work, they break script atomicity and add unnecessary complexity.

The proper approach combines two critical flags:

cpio --extract --make-directories --no-absolute-filenames < archive.cpio -D /target/path

Breaking this down:

  • --extract (-i): Standard extraction mode
  • --make-directories (-d): Creates parent directories as needed
  • --no-absolute-filenames: Forces relative path interpretation
  • -D: Sets the target directory (works with RHEL 4's GNU cpio)

Here's how you'd use this in a deployment script:

#!/bin/bash
BACKUP_FILE="/var/backups/configs-2023.cpio"
DEPLOY_PATH="/opt/app/current_configs"

if [ -f "$BACKUP_FILE" ]; then
    cpio -idm --no-absolute-filenames < "$BACKUP_FILE" -D "$DEPLOY_PATH" || {
        echo "Extraction failed!" >&2
        exit 1
    }
    chmod -R 750 "$DEPLOY_PATH"
fi

For particularly stubborn archives:

# Force overwrite existing files
cpio -idmu --no-absolute-filenames < archive.cpio -D /target

# Verbose extraction with directory creation
cpio -idmv --no-absolute-filenames < archive.cpio -D /target | logger -t cpio_extract

The traditional approach has several flaws:

# Problematic example:
original_dir=$(pwd)
cd /target || exit 1
cpio -i < ../archive.cpio
cd "$original_dir" || exit 1

This creates:

  • Race conditions if the directory changes
  • Potential exit traps that don't properly reset
  • Difficulty tracking file operations

The -D method maintains script context while providing clean path specification.

If you encounter a version without -D support:

(cd /target && cpio -idm --no-absolute-filenames) < archive.cpio

This subshell approach contains the directory change without affecting the main script.