This question already has an answer here:

I have some filenames as such.


one character followed by 1 or 2 numbers followed by .txt.gz. I would like to add single numbers with a zero before the number like below.


I tried something like this but it doesn't seem to work.

find . | grep -E "[a-z][0-9]{1}\.+" | sed -er s/\([a-z]\)\([0-9]{1}\)\(.txt.gz\)/\10\2\3/

My logic was to first grep single digit filenames, then split into 3 parts character, number and .txt.gz and then add add 0 before number. But I can't get it to work. And I am not sure about the rename part.

marked as duplicate by don_crissti, sam, Rui F Ribeiro, Thomas Dickey, mdpc Jun 29 '16 at 23:43

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    rename 's/(\d+)/sprintf "%02d", $1/ge' *.txt.gz – Satō Katsura Jun 29 '16 at 18:35
  • I'm not convinced this is an exact dupe, as the linked question assumes a fixed filename prefix whereas this one is variable. – Edward Falk Jun 29 '16 at 18:36
  • @EdwardFalk - it's not "an exact dupe" but manatwork's solutions there should do (or Gilles' one, slightly modified: zmv -n '([^0-9])([0-9]##).(txt.gz)' '$1${(l:2::0:)2}.$3') – don_crissti Jun 29 '16 at 18:43
  • @SatoKatsura The rename doesn't work for me. – rmf Jun 29 '16 at 19:26
  • 1
    You prolly have rename from util-linux which does not work with regex and has a different syntax. – don_crissti Jun 29 '16 at 19:29

I would do it like this: for f in [a-z][0-9].txt.gz; do mv $f "${f:0:1}0${f:1}" done

I adapted this from something else (which used awk because it needed more, but thanks to a comment I made it better).

  • You don't need awk for this job, see my comment on OP's answer. – don_crissti Jun 29 '16 at 22:17
  • Updated answer as per that. I hadn't seen your comment before I headed off to write my answer. Seems our minds were running in the same gutter... – MAP Jun 29 '16 at 22:27

This would do it:

find . -name '??.txt.gz' | sed -e 's/..\(.\)\(.*\)/mv \1\2 \10\2/' > /tmp/cmds
sh /tmp/cmds

The find command gets the list of files that need to be renamed. The sed command constructs a list of mv commands to do what you want. Those get written to a file and then executed as a shell script.

I'm sure there's a way to do this as a one-liner, but I'm feeling lazy.

  • But check to see if you have the version of rename on your system that takes regexes. If so, it will do what you want. – Edward Falk Jun 29 '16 at 18:46
  • this doesn't seem to work. – rmf Jun 29 '16 at 19:25
  • Worked on my Mac, using the filenames you gave in your example. What part failed? Did you get /tmp/cmds? What was in it? – Edward Falk Jun 29 '16 at 20:34
  • 1
    You could make it all one line by just piping int sh rather than writing the file. Of course, then you couldn't ask the clarifying "what was in the file" comment. – MAP Jun 29 '16 at 22:01

Based on Padding a number in a filename to a fixed length, I found this to work for me. This is a hacky way and I am surprised there is no proper/simple way to do this and without additional programs or functions.

var=$(find . | grep -E "[a-z][0-9]{1}\.+" | sed 's/\.\///')
for f in $var; do
    alpha=$(basename $f .gz | cut -c1-1)
    num=$(basename $f .gz | grep -o "[0-9]")
    zero=$(echo "0")
    new_name=$(printf "$alpha$zero$num.txt.gz")
    echo "Renaming $f to $new_name"
    [ ! -f $new_name ] && mv $f $new_name
  • var=$(find..) is pretty bad and ugly, above all... the {1} after [0-9] is superfluous and... zero=$(echo "0") ???? That one really takes the cake ! I mean really, you can just do for f in [a-z][0-9].txt.gz; do echo mv "$f" "${f:0:1}0${f:1}"; done and remove the echo if all's fine. – don_crissti Jun 29 '16 at 21:32

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