I've got a directory with 15000 zip files. I'd like to rename all files which, when unzipped, contain a file of the form


where YYYYMMDD happens to be a date but for the purposes of this problem is any string of exactly 8 digits. Then, the zip file itself should be renamed to


I have gotten as far as the following command line but I don't know how to capture the YYYYMMDD from the contained file to use in order to rename the zip files:

find . -iname '*.zip' | while read file; do unzip -l "$file" | grep -q -P '\d{8}_IPC.csv' && echo $file; done 2>&- 

Thank you for reading.

1 Answer 1

find . -iname '*.zip' -exec bash -c 'name=$(unzip -qql "$1"  '*_IPC.csv' | grep -oE '[[:digit:]]{8}_IPC.csv' | head -n1); [ "$name" ] && mv "$1" "${name%csv}zip"' none {} ';'

How it works

This command has the form:

find . -iname '*.zip' -exec bash -c '...' none {} ';'

This searches for .zip file in the current directory and all subdirectories under it. For each such file found the bash command in single quotes is executed. The name of the file found is supplied at argument one, $1, to the bash command. In our case, the bash command has two parts. The first extracts the csv file name and saves it in bash variable name:

name=$(unzip -qql "$1"  '*_IPC.csv' | grep -oE '[[:digit:]]{8}_IPC.csv' | head -n1)

The above uses command substitution: the command inside $(...) is run and its standard out is captured. In this case, we assign it to the variable name. The command unzip -qql "$1" '*_IPC.csv' quietly extracts all file names from the zip file that match the glob *_IPC.csv. We don't need to limit to the glob *_IPC.csv but, if the zip file has many files in it, this may speed things up.

The grep command, rep -oE '[[:digit:]]{8}_IPC.csv' further selects only those name that start with 8 digits. The head -n1 command selects the first such name found. If there was only one such name, head -n1 wouldn't be needed. But, keeping head could speed things up because it causes the pipeline to terminate after the first match.

The second part tests that we succeeded in getting a non-empty name and, if so, renames the zip file:

[ "$name" ] && mv "$1" "${name%csv}zip"

The above uses suffix removal to change the csv file name to a zip file name. ${name%csv} returns $name after having removed the suffix csv. ${name%csv}zip adds a zip suffix.

  • This worked perfectly. Outstanding! Thank you.
    – Curt
    Sep 25, 2015 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.