33

Trying to add a zero before the varaible if it's less than 10 and create said directory. I can't seem to get the zero to add correctly. Keeps resulting in making 02.1.2011, 02.2.2011 etc,etc.

i=0
for i in {01..31}
do
    if $i > 10
        then
            mkdir $path/02.0$i.2011
        else    
            mkdir $path/02.$i.2011
    fi
done
Colby
  • 339
  • 1
  • 3
  • 3
  • possible duplicate of [How to zero pad a sequence of integers in bash so that all have the same width?](http://stackoverflow.com/questions/8789729/how-to-zero-pad-a-sequence-of-integers-in-bash-so-that-all-have-the-same-width) – Ciro Santilli OurBigBook.com Jul 24 '15 at 17:02
  • See how to zero-padding with parameter expansion: https://askubuntu.com/a/1257316/670392 – Noam Manos Jul 08 '20 at 10:34

11 Answers11

65

You can replace the whole lot with:

for day in 0{1..9} {10..31} ; do
    mkdir ${path}/02.${day}.2011
done

while still not having to start up any external processes (other than what may be in the loop body).

That's probably not that important here since mkdir is not one of those things you tend to do a lot of in a tight loop but it will be important if you write a lot of your quick and dirty code in bash.

Process creation is expensive when you're doing it hundreds of thousands of times as some of my scripts have occasionally done :-)

Example so you can see it in action:

pax$ for day in 0{8..9} {10..11}; do echo ${day}; done
08
09
10
11

And, if you have a recent-enough version of bash, it will honor your request for leading digits:

A sequence expression takes the form {x..y[..incr]}, where x and y are either integers or single characters, and incr, an optional increment, is an integer.

When integers are supplied, the expression expands to each number between x and y, inclusive.

Supplied integers may be prefixed with 0 to force each term to have the same width. When either x or y begins with a zero, the shell attempts to force all generated terms to contain the same number of digits, zero-padding where necessary.

So, on my Debian 6 box, with bash version 4.1.5:

pax$ for day in {08..11} ; do echo ${day} ; done
08
09
10
11
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Bonus for the comment about more recent bash versions supporting leading zeros! – timbo Jun 14 '15 at 22:45
  • For some reason, my bash 5.0.7 installation via macports doesn't support prefixing with 0. But specifying multiple non-consecutive increments is amazing. – zymhan Jul 18 '19 at 21:42
30

You can use

$(printf %02d $i)

To generate the numbers with the format you want.

for i in $(seq 0 1 31)
do
    mkdir $path/02.$(printf %02d $i).2011
done
Jesse Cohen
  • 4,010
  • 22
  • 25
  • I'd forgotten about seq. But just `seq 31` would do the trick, I think. OP didn't want 0 and the default for both `first` and `increment` is 1. – paxdiablo Feb 24 '11 at 01:08
  • 7
    `seq -w` generates numbers with leading zeros. – Andras Nemeth May 30 '14 at 05:16
  • Nice that it is easy to integrate into old echo statements like `echo "this is a $var" `-> `echo "this is a $(printf %03d $var)"` – akozi Oct 09 '18 at 14:44
16

Better:

for i in $(seq -f %02g 1 31)
do
    mkdir "$path/02.$i.2011"
done

Or even:

for i in {01..31}
do
    mkdir "$path/02.$(printf "%02d" $i).2011"
done
Juliano
  • 39,173
  • 13
  • 67
  • 73
6

In Bash 4, brace range expansions will give you leading zeros if you ask for them:

for i in {01..31}

without having to do anything else.

If you're using earlier versions of Bash (or 4, for that matter) there's no need to use an external utility such as seq:

for i in {1..31}

or

for ((i=1; i<=31; i++))

with either of those:

mkdir "$path/02.$(printf '%02d' "$i").2011"

You can also do:

z='0'
mkdir "$path/02.${z: -${#i}}$i.2011"

Using paxdiablo's suggestion, you can make all the directories at once without a loop:

mkdir "$path"/02.{0{1..9},{10..31}}.2011
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
3
$ seq --version | head -1
seq (GNU coreutils) 8.21
$ seq -f "%02g" 1 10
01
02
03
04
05
06
07
08
09
10
Amin Abbaspour
  • 1,111
  • 11
  • 10
3

Will this work for you?

zeroes="0000000"
pad=$zeroes$i
echo ${pad:(-2)}
Adam Liss
  • 47,594
  • 12
  • 108
  • 150
2

How about using equal-width option (-w) in seq command:

for i in `seq -w 1 31`; do echo $i; done

It returns:

01
02
03
...
31
Ashkan Mirzaee
  • 300
  • 4
  • 14
0

Here's what I did for a script where I'm asking for a day, range of days, regex, etc. with a default to the improved regexes shared by paxdiablo.

for day in $days
    do if [ 1 -eq "${#day}"] ; then
        day="0$day"
    fi

I just run through this at the beginning of my loop where I run a bunch of log analysis on the day in question, buried in directories with leading zeroes.

jth
  • 140
  • 6
0

I created this simple utility to perform this, Good Luck , hope this helps stack'ers!!

for i in {1..24}
do
charcount=`echo $i|wc -m`
count=`expr $charcount - 1`
if [ $count -lt 2 ];
then
i="0`echo $i`"
fi
echo "$i"
done
Andrew Regan
  • 5,087
  • 6
  • 37
  • 73
0

Your if/then statement is backwards. You are adding a 0 when it is a above 10, not adding one when it is below.

Another bug is that you make the cutoff strictly greater than 10, which does not include 10, even though 10 is two digits.

Kevin Dolan
  • 4,952
  • 3
  • 35
  • 47
0
path=/tmp
ruby -rfileutils -e '1.upto(31){|x| FileUtils.mkdir "'$path'/02.%02d.2011" % x}'
kurumi
  • 25,121
  • 5
  • 44
  • 52