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.