2

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!

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
  • Copy/paste your shell script into http://shellcheck.net and fix the issues it tells you about and then let us know if you still have a question. Also don't use all upper case variable names, see [correct-bash-and-shell-script-variable-capitalization](https://stackoverflow.com/questions/673055/correct-bash-and-shell-script-variable-capitalization). – Ed Morton Nov 04 '21 at 17:27

3 Answers3

3

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.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
2

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")
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • Unfortunately, this part (FSIContract)is not same for all files. It changes like this "FSICustomerContact", "FSILocation" and etc. – codehunter-py Nov 04 '21 at 17:09
  • This doesn't matter. What the commands I show do is remove the first and 12 last characters. They don't care what's in between. Give them a try. – Renaud Pacalet Nov 04 '21 at 17:11
  • But of course yours does work only for PFSI4C.CSC.CCC.FSIContractData20211008.zip not PFSI4C.CSC.CCC.FSICustomerContact20211008.zip, PFSI4C.CSC.CCC.FSILocation20211008.zip – codehunter-py Nov 04 '21 at 17:11
  • Alright I will give a try again – codehunter-py Nov 04 '21 at 17:12
  • I am not sure I understand why you think it will not work but I tested with your two other examples and it worked like a charm. The first version (bash parameter substitution) works only if the names end with a date on 8 characters followed by the `.zip` extension. The two others with sed tolerate dates on any number of digits. – Renaud Pacalet Nov 04 '21 at 17:20
  • NEW_FILENAME=$(sed -E 's/.(.*[^0-9])?[0-9]*\.zip/T\1'"20${DATE}"'.zip/' <<< "$FILENAME") worked perfectly by adding 20 in the beginning of $DATE. Thanks much! – codehunter-py Nov 04 '21 at 17:21
  • Oh, sorry, I did not realize that your `DATE` is on 6 digits only. Why don't you use `date +%Y%m%d` instead of `date +%y%m%d`? Edited my answer accordingly. – Renaud Pacalet Nov 04 '21 at 17:23
  • Ugh, that is long story :D But make long story short, I work on automation with shell scripts where we use $DATE to list the other files with the `find` command. Terrible – codehunter-py Nov 04 '21 at 17:30
1

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.

markp-fuso
  • 28,790
  • 4
  • 16
  • 36