Renaming multiple files with multiple field separator in awk

Viewed 122

I need to rename following file likewise from PFSI4C.CSC.CCC.FSIContractData20211008.zip to TFSI4C.CSC.CCC.FSIContractData20211104.zip.

Every file's name should start with "T" and end up with current system date + .zip"

I am trying to loop over files and it looks like this:

for FILENAME in PFSI4C.CSC.CCC.FSIContractData20211008; do
    NEW_FILENAME_HEADER=`echo $FILENAME | awk -F "." '{ print $1"."$2"."$3 }'` # which would takes PFSI4C.CSC.CCC.
    NEW_FILENAME_SUFFIX=`echo $FILENAME | awk -F "[.|Data20]" '{ print "."$4 }'` # this part where I can't figure out to take only "FSIContract"
    NEW_FILENAME="${NEW_FILENAME_HEADER}.""${NEW_FILENAME_SUFFIX}""Data20""${DATE}".zip" # which should make "TFSI4C.CSC.CCC.FSIContractData20211104.zip."
    mv $FILENAME $NEW_FILENAME
  done
  

FYI $DATE in our script defined like this: DATE='date +'%y%m%d' for example 211104

Thanks in advance!

3 Answers

With Perl's rename command you could try following code. I am using -n option here to test it in DRY RUN mode it will only print the file names from which file name(current) to which file name(required one) will be changed; remove -n in code once you are satisfied with shown output. Also DATE variable (DATE='20211104') is a shell variable which contains value of date needed to be in new file name.

rename -n 's:^.(.*)\d{8}(\.zip)$:T$1$2:; s:\.zip$:'"$DATE"'.zip:' *.zip

Output will be as follows:

rename(PFSI4C.CSC.CCC.FSIContractData20211008.zip, TFSI4C.CSC.CCC.FSIContractData20211104.zip)

Explanation of rename code:

  • -n: To run rename command in DRY RUN mode.
  • s:^.(.*)\d{8}(\.zip)$:T$1$2:;: Running 1st set of substitution in rename code. Where it creates 2 capturing group, 1st capturing group has everything from 2nd character onwards to just before 8 digits AND 2nd capturing group contains .zip at the end of filename. While substitution substituting it with T1$2 as per requirement.
  • s:\.zip$:'"$DATE"'.zip:: Running 2nd set of substitution in rename code. Where .zip$ with shell variable DATE along with .zip as per requirement.

First of all you should get the current date with date +%Y%m%d (4-digits year) instead of date +%y%m%d (2-digits year). The following assumes you do that. Prepend 20 to $DATE if it is not an option.

If your file names all look as the example you show bash substitutions can do it. First compute the length, extract the characters from second to last before date, prepend T, append $DATE.zip:

len="${#FILENAME}"
NEW_FILENAME="T${FILENAME:1:$((len-13))}$DATE.zip"

But you could also use sed, it offers a bit more flexibility. For instance it can deal with ending dates on a variable number of digits:

NEW_FILENAME=$(echo "$FILENAME" | sed 's/.\(.*[^0-9]\)\?[0-9]*\.zip/T\1'"$DATE"'.zip/')

Or, a bit more elegant with bash (here strings) and GNU sed or another sed that supports the -E option (for extended regular expressions):

NEW_FILENAME=$(sed -E 's/.(.*[^0-9])?[0-9]*\.zip/T\1'"$DATE"'.zip/' <<< "$FILENAME")

Assumptions:

  • replace first character (P in OP's sample) with T
  • replace last 10 characters (YYMMDD.zip) with $DATE.zip (OP has already defined $DATE)
  • all files contain 20YYMMDD so we don't need to worry about names containing strings like 19YYMMDD and 21YYMMDD

One idea using parameter substitutions (which also eliminates the overhead of subprocess calls to execute various echo, awk and sed commands):

DATE='211104'
FILENAME='PFSI4C.CSC.CCC.FSIContractData20211008.zip'

NEWFILENAME="T${FILENAME/?}"                           # prepend "T"; "/?" => remove first character
NEWFILENAME="${NEWFILENAME/??????.zip}${DATE}.zip"     # remove string "??????.zip"; append "${DATE}.zip"

echo mv "${FILENAME}" "${NEWFILENAME}"

This generates:

mv PFSI4C.CSC.CCC.FSIContractData20211008.zip TFSI4C.CSC.CCC.FSIContractData20211104.zip

Once OP is satisified with the accuracy of the code the echo can be removed to enable execution of the mv command.

Related