I have a directory that has a large number of files. These files are named according to the following system: "Var1_X_Var2_Y_Var3_Z_data_N.txt" Where X, Y, and Z are many different numbers, and N ranges from 1 to 30.

To use these files in my next script i need to add a leading zero for files where N is 1 to 9.

On my ubuntu machine I use the following command

rename  's/_1.txt/_01.txt/' *

and repeat it from 1 to 9.
However, this command will not work on a cluster I am using. I need a unix or bash or python alternative.

(note: I know there are many related questions on stackexchange, but all of them seem to use cases in which all the files share the same stem. I have destroyed several files trying to apply those solutions)


You want the N in Var1_X_Var2_Y_Var3_Z_data_N.txt to be a zero-filled two-digit integer.

Assuming all affected files matches the pattern *_[0-9].txt:

for name in *_[0-9].txt; do
    stem="${name%.txt}"    # remove the ".txt" suffix
    num=${stem##*_}        # extract the number at the end
    newname="${stem%[0-9]}$( printf '%02d.txt' "$num" )" # put it back together

    printf 'Would rename "%s" into "%s"\n' "$name" "$newname"
    # mv -- "$name" "$newname"
  • ${name%.txt} removes the .txt from the end of $name, the original filename. This creates the "stem", which is not really the stem since it still has the number at the very end.
  • ${stem##*_} removes everything up to and including the last underscore in $stem.
  • ${stem%[0-9]} is the stem without the number at the end (e.g. Var1_X_Var2_Y_Var3_Z_data_).
  • printf '%02d.txt' "$num" produces a zero-filled two-digit number from $num, followed by the string .txt.

Given a directory with the files

Var1_X_Var2_Y_Var3_Z_data_1.txt              Var1_X_Var2_Y_Var3_Z_data_23.txt
Var1_X_Var2_Y_Var3_Z_data_10.txt             Var1_X_Var2_Y_Var3_Z_data_24.txt
Var1_X_Var2_Y_Var3_Z_data_11.txt             Var1_X_Var2_Y_Var3_Z_data_25.txt
Var1_X_Var2_Y_Var3_Z_data_12.txt             Var1_X_Var2_Y_Var3_Z_data_26.txt
Var1_X_Var2_Y_Var3_Z_data_13.txt             Var1_X_Var2_Y_Var3_Z_data_27.txt
Var1_X_Var2_Y_Var3_Z_data_14.txt             Var1_X_Var2_Y_Var3_Z_data_28.txt
Var1_X_Var2_Y_Var3_Z_data_15.txt             Var1_X_Var2_Y_Var3_Z_data_29.txt
Var1_X_Var2_Y_Var3_Z_data_16.txt             Var1_X_Var2_Y_Var3_Z_data_3.txt
Var1_X_Var2_Y_Var3_Z_data_17.txt             Var1_X_Var2_Y_Var3_Z_data_30.txt
Var1_X_Var2_Y_Var3_Z_data_18.txt             Var1_X_Var2_Y_Var3_Z_data_4.txt
Var1_X_Var2_Y_Var3_Z_data_19.txt             Var1_X_Var2_Y_Var3_Z_data_5.txt
Var1_X_Var2_Y_Var3_Z_data_2.txt              Var1_X_Var2_Y_Var3_Z_data_6.txt
Var1_X_Var2_Y_Var3_Z_data_20.txt             Var1_X_Var2_Y_Var3_Z_data_7.txt
Var1_X_Var2_Y_Var3_Z_data_21.txt             Var1_X_Var2_Y_Var3_Z_data_8.txt
Var1_X_Var2_Y_Var3_Z_data_22.txt             Var1_X_Var2_Y_Var3_Z_data_9.txt

.. that loop would produce

Would rename "Var1_X_Var2_Y_Var3_Z_data_1.txt" into "Var1_X_Var2_Y_Var3_Z_data_01.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_2.txt" into "Var1_X_Var2_Y_Var3_Z_data_02.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_3.txt" into "Var1_X_Var2_Y_Var3_Z_data_03.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_4.txt" into "Var1_X_Var2_Y_Var3_Z_data_04.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_5.txt" into "Var1_X_Var2_Y_Var3_Z_data_05.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_6.txt" into "Var1_X_Var2_Y_Var3_Z_data_06.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_7.txt" into "Var1_X_Var2_Y_Var3_Z_data_07.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_8.txt" into "Var1_X_Var2_Y_Var3_Z_data_08.txt"
Would rename "Var1_X_Var2_Y_Var3_Z_data_9.txt" into "Var1_X_Var2_Y_Var3_Z_data_09.txt"

Remove the commented out mv at the end of the loop to actually rename the files.

|improve this answer|||||
  • thank you for comments in the code that explain what each part does. – Bobby M May 21 '18 at 17:44
find -name "*_[1-9].txt" -exec sh -c 'echo $1 ${1%_*}_0${1##*_}' _ {} \;
  • The $1 is substituting with the file found.
  • The ${1%_*} is removing everything after last underscore and underscore itself.
  • This _0 just prints an underscore followed by a zero.
  • This ${1##*_} removes everything before last underscore and underscore itself.

replace echo with mv for renaming on files.

I used this to crated 3o files

touch Var1_${RANDOM}_Var2_${RANDOM}_Var3_${RANDOM}_data_{1..30}.txt
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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