How to extract files in place using find

4 minute read

Published:

Problem: How to find files and execute commands according to their names/paths

Consider this case: I want to extract all the tar files to their own folders.

$ tree . -P '*[me].tar'
.
└── parsec-2.1
    ├── config
    └── pkgs
        ├── apps
        │   ├── blackscholes
        │   │   ├── inputs
        │   │   │   ├── input_simlarge.tar
        │   │   │   └── input_simmedium.tar
        │   │   └── parsec
        │   ├── bodytrack
        │   │   ├── inputs
        │   │   │   ├── input_simlarge.tar
        │   │   │   └── input_simmedium.tar
        │   │   └── parsec
        │   ├── facesim
        │   │   ├── inputs
        │   │   │   ├── input_simlarge.tar
        │   │   │   └── input_simmedium.tar
        │   │   └── parsec
.....

Solution: use find with -exec to execute command

find ./parsec-2.1 -name '*.tar' -execdir tar -xvf '{}' \;

Here, -execdir <command> \; will execute command at the directory that the file is found.

'{}' is the name of the file found by find.


The content below is about furthur understanding and usage of -exec, and is not needed for solving the initial probelm.

Advanced: rename file’s extension

According to https://askubuntu.com/questions/35922/how-do-i-change-extension-of-multiple-files-recursively-from-the-command-line , you can also rename the file’s extenstion:

Eg. rename “123.avi” to “123.mp4”

find /the/path -depth -name "*.avi" -exec sh -c 'mv "$1" "${1%.avi}.mp4"' _ {} \;

In case anyone else is wondering what the underscore is doing in the first command, it’s needed because with sh -c the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. So the _ is a dummy argument, and ‘{}’ is the first positional argument to sh -c

Advanced: convert videos to another format

The following command will convert all the DAT file to mp4 using ffmpeg.

find . -name '*.DAT' -execdir sh -c 'ffmpeg -i "$1" "${1%.DAT}.mp4"' _ {} \;

Note: ffmpeg is by default multithreaded.