Last active
September 15, 2026 01:00
-
-
Save GeorgeTR1/4912dc17d62cb07e319594de2b30fce6 to your computer and use it in GitHub Desktop.
Safely extract tar files without polluting the current directory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # usage: ./tarex.sh example.tar.gz | |
| # will extract example.tar.gz, making sure it is always contained in a single | |
| # directory in the current directory | |
| # Keeps directory clean from "tar bombs" by creating a directory to extract the tar file into, | |
| # and then only copying the results back to the current directory if there is only one file | |
| # or directory, indicating that the results were contained in one directory | |
| # tar file to extract | |
| FILE=$1 | |
| # NAME becomes file name without extension | |
| # exam.ple.tar.gz -> exam.ple | |
| # exam.ple.tar -> exam.ple | |
| NAME=${FILE%.*} | |
| NAME=${NAME%.tar} | |
| # random string of characters to avoid file name conflict, | |
| # the chance that a file will be named this is astronomically low. | |
| # I generated this with Python, it wasn't just me typing "randomly" | |
| # Even if a malicious actor named a file this, it wouldn't do any harm, | |
| # so no need to worry | |
| RAND=gwrvegvusbqifcg | |
| # create a directory with the same name as the .tar file, minus extensions | |
| mkdir "$NAME" | |
| # a uses the file extension to infer compression type (gz, bz2, xz, none, etc.) | |
| # -C changes directory to the one we just created before extracting files | |
| if tar xaf "$FILE" -C "$NAME" | |
| then # tar command was successful | |
| count=0 # represents number of files/directories in the directory we created | |
| # (non-recursive) | |
| for _ in "$NAME"/*; do # "_" is a garbage variable we discard names into, | |
| # we only care if the loop runs more than once, indicating | |
| # the output from tar wasn't contained in one directory | |
| # (or wasn't just one file) | |
| if [ $count = 1 ]; then | |
| count=2 | |
| break | |
| fi | |
| count=1 | |
| done | |
| # if the results were contained (as we would hope), we copy the directory that was | |
| # extracted out of the container directory and into the current directory | |
| if [ $count = 1 ]; then | |
| # rename the container directory to the random string of letters to guarantee | |
| # it has a different name than the directory that was extracted | |
| # For example, it would be very typical that when you extract "example.tar.gz" | |
| # you get a directory called "example" that contains all other files/directories | |
| mv "$NAME" $RAND | |
| mv $RAND/* ./ | |
| rmdir $RAND | |
| fi | |
| else | |
| # if tar failed, remove the directory we created to clean up | |
| rmdir "$NAME" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment