Incrementing parts of ten digits number by parts

I have number in file which contains date and serial number:
2013101000.

The last two digits are serial number (00). So maximum of serial number is 100.

After reaching 100 it becomes 00 with incrementing 10 which is day with max 31.

after reaching 31 it becomes 00 and increments 10 which is month with maximum 12.

so basically when I run code it rewrites 10 digits with above conditions... My problem is that I dont know how to separate these 4 numbers. If I have "." or smth like that among them then it would be easier but here I have no idea.....

So example:
cat file
2013113098

sh my_code
cat file
2013113099

sh my_code
cat file
2013113100

sh my_code
cat file
2013113101

then I sh my_code 100 times
cat file
2013120100

n=2013113098
echo "${n:0:4} ${n:4:2} ${n:6:2} ${n:8:2}"

so basically u divided my number into 4 parts right?! So I can increment independently, right? :wink:
For incrementing I just add 1 to ${n:8:2} for example, right?

Longhand on OSX 10.7.5 default bash terminal:-

Last login: Thu Oct 10 07:41:49 on ttys000
AMIGA:barrywalker~> data=2013101173
AMIGA:barrywalker~> data1=${data:0:4}
AMIGA:barrywalker~> echo "$data1"
2013
AMIGA:barrywalker~> data2=${data:4:2}
AMIGA:barrywalker~> echo "$data2"
10
AMIGA:barrywalker~> data3=${data:6:2}
AMIGA:barrywalker~> echo "$data3"
11
AMIGA:barrywalker~> data4=${data:8:2}
AMIGA:barrywalker~> echo "$data4"
73
AMIGA:barrywalker~> data4=$[ ( $data4 + 1 ) ]
AMIGA:barrywalker~> echo "$data4"
74
AMIGA:barrywalker~> echo "$data1 $data2 $data3 $data4"
2013 10 11 74
AMIGA:barrywalker~> _

Hope this helps...

1 Like

Whether you want like this

$ cat file
2013113098
$ cat serial.sh

  awk '

BEGIN{
         OFS="\t"
         printf RS OFS "Enter Year till which you want to generate serial number : "
         getline stop < "-"
         printf OFS "Enter Output Filname :  "
         getline out < "-" 
         nonleap = "31,28,31,30,31,30,31,31,30,31,30,31"
         leap     = "31,29,31,30,31,30,31,31,30,31,30,31"
         split(nonleap,NLP,",")
         split(leap,LP,",")
         if(!stop){printf RS "\t" "No User Input...Exiting" RS RS;exit }
     }

function serial(start,m,d,y){
                                   for(s=start;s<=100;s++)    
                                               if(out){
                                                       print y sprintf("%.2d",m) sprintf("%.2d",d) sprintf("%.3d",s) >out
                                                      } 
                                              else
                                                     {
                                                        print y sprintf("%.2d",m) sprintf("%.2d",d) sprintf("%.3d",s)
                                                     }
                            }

    {
        ser=substr($1,8,10)
        day=substr($1,7,2)
        mon=substr($1,5,2)        
        year=substr($1,0,4)

        if(stop~/[A-Za-z]/){print "Year should be Integer...Exiting" RS;exit}
        if(stop%1!=0){print "Year cannot be float...Exiting" RS;exit}
        if(stop<year){print "Year should be Equal or Greater than  Existing Serial Number...Exiting" RS;exit}

        f=1
        for(y=year;y<=stop;y++){
                mon=(f==1)?mon:1
                
        f=0
                g=1        
                for(m=mon;m<=12;m++)
                    {
                        dend=((y%4==0) || (y%100==0) || (y%400==0))?LP[m]:NLP[m]
                        day=(g==1)?day:1
                        ser=(g==1)?ser:0
                        for(day=day;day<=dend;day++){serial(ser,m,day,y)}
                g=0
                    }                
                                 }
            
     }' file

Resulting

$ sh serial.sh

  Enter Year till which you want to generate serial number : 2013
  Enter Output Filname :  test.txt

20131130098
20131130099
20131130100
20131201000
20131201001
20131201002
20131201003
20131201004
20131201005
20131201006

I am not fan of awk, also dont understand it. So i will try to replace it with statements... Anyway, thank u so much:)

Sorry I was not knowing :slight_smile:

1 Like

In the future, to not waste anyone's time, please mention in your problem statement that you are not interested in AWK solutions (or that you require a sh-only solution). This same issue occurred in your other thread.

There is no reason for you to apologize.

Regards,
Alister

1 Like

Yeh Alister I really disappointed, I have one suggestion don't know its good or not...whether its possible to keep one option while posting thread that interested solution in awk, shell, perl,php,c,etc

If you would like to contribute code that the OP is not interested in using, feel free. I don't see why it would be a problem. The OP can simply ignore it, and your contribution may be of interest to someone else (if not in the present, then perhaps in the future).

My previous post's intent is solely to request that the OP make any restrictions known at the time that help is requested.

Regards,
Alister

Hello I am still working on my code..... The issue I faced is that i have to have 00 01 02 03 04 05 06 07 08 09 010 011 ...099 100. But my numbers are 1 2 3 4 5 ...How I can change it to different format? Moreover, my number is in the file....so basically it reads number in file compare and increment the number and rewrite file with new number :wink: But my piece of code gives me nothing lol :frowning:

for example: file kuku.txt
cat kuku.txt
->2013081001
after running my code
cat kuku.txt
->2013081002

DIR="/Users/Natalie/1/kuku.txt"
n="Users/Natalie/1/$kuku.txt"
#echo "${n:0:4} ${n:4:2} ${n:6:2} ${n:8:2}"

fourthoct=${n:0:4}
thirdoct=${n:4:2}
secondoct=${n:6:2}
firstoct=${n:8:2}

if [ "$(ls -A $DIR)" ] then
sort /Users/Natalie/1/kuku.txt | tail -1 |

     while read firstoct secondoct thirdoct fourthoct
               do
            if [ $((++firstoct)) -eq 101 ]
                   then

                  firstoct=0
                   if [ $((++secondoct)) -eq 32 ]
                        then
 secondoct=0
                         if [ $((++thirdoct)) -eq 13 ]
                               then
                                thirdoct=0
                                   ((++fourthoct))
fi
fi
fi

echo $fourthoct$thirdoct$secondoct$firstoct >kuku.txt
done
else
echo "Hi its new file" >kuku.txt
fi

Here is a simple starter solution...

#!/bin/bash --posix
# num.sh
data="2013102100"
data1="${data:0:4}"
data2="${data:4:2}"
data3="${data:6:2}"
data4="${data:8:2}"
echo "$data1 $data2 $data3 $data4"
for n in {1..99}
do
	data4="0$n"
	echo "$data1 $data2 $data3 $data4"
done
data4="100"
echo "$data1 $data2 $data3 $data4"

Results...

2013 10 21 00
2013 10 21 01
2013 10 21 02
2013 10 21 03
2013 10 21 04
2013 10 21 05
2013 10 21 06
2013 10 21 07
2013 10 21 08
2013 10 21 09
2013 10 21 010
2013 10 21 011
2013 10 21 012
2013 10 21 013
2013 10 21 014
2013 10 21 015
2013 10 21 016
2013 10 21 017
2013 10 21 018
2013 10 21 019
2013 10 21 020
2013 10 21 021
2013 10 21 022
2013 10 21 023
2013 10 21 024
2013 10 21 025
2013 10 21 026
2013 10 21 027
2013 10 21 028
2013 10 21 029
2013 10 21 030
2013 10 21 031
2013 10 21 032
2013 10 21 033
2013 10 21 034
2013 10 21 035
2013 10 21 036
2013 10 21 037
2013 10 21 038
2013 10 21 039
2013 10 21 040
2013 10 21 041
2013 10 21 042
2013 10 21 043
2013 10 21 044
2013 10 21 045
2013 10 21 046
2013 10 21 047
2013 10 21 048
2013 10 21 049
2013 10 21 050
2013 10 21 051
2013 10 21 052
2013 10 21 053
2013 10 21 054
2013 10 21 055
2013 10 21 056
2013 10 21 057
2013 10 21 058
2013 10 21 059
2013 10 21 060
2013 10 21 061
2013 10 21 062
2013 10 21 063
2013 10 21 064
2013 10 21 065
2013 10 21 066
2013 10 21 067
2013 10 21 068
2013 10 21 069
2013 10 21 070
2013 10 21 071
2013 10 21 072
2013 10 21 073
2013 10 21 074
2013 10 21 075
2013 10 21 076
2013 10 21 077
2013 10 21 078
2013 10 21 079
2013 10 21 080
2013 10 21 081
2013 10 21 082
2013 10 21 083
2013 10 21 084
2013 10 21 085
2013 10 21 086
2013 10 21 087
2013 10 21 088
2013 10 21 089
2013 10 21 090
2013 10 21 091
2013 10 21 092
2013 10 21 093
2013 10 21 094
2013 10 21 095
2013 10 21 096
2013 10 21 097
2013 10 21 098
2013 10 21 099
2013 10 21 100
1 Like

Thanks. But I kind of do not know where to add this logic to my code.....Gives me error everywhere....

I have no doubt some better solution may exist but until someone shoot one ...
For sure this code can be enhanced a lot (for example adding checking conditions to ensure that the given argument is made of 10 digits) but it may give some clue (at least i hope so).
You can also put it into a function that can then be called later on.
Converting date to second , adding 1 day in second , and converting it back to date make it able to handle leap year and avoid tedious date calculations :

$ cat increm
#!/usr/bin/sh

d=${1%??}
i=${1#$d}

if [ $i -ge 99 ]
then i=0
_s=$( date -u -d "$(echo $d | sed 's/../-&-/3')" +%s )
n=$(( $_s + 86400 ))
_d=$( date -u -d"1970-01-01 $n sec GMT" +%Y%m%d )
d=$_d
else 
i=$(( i + 1 ))
fi
printf "%s%02d\n" $d $i

$ sh increm 1988022899
1988022900
$ sh increm 1988022999
1988030100
$ sh increm 2013103099
2013103100
$ sh increm 2013103100
2013103101
$ sh increm 2013103199
2013110100
$

You are changing the goalposts!
Please be more accurate and specific.
I have temporarily removed the loop for obvious reasons.
Fianlly if I am misunderstanding your requirements, then my apologies...

#!/bin/bash --posix
# num.sh
# Create a null file for fullness IF you want to...
# > /tmp/kuku.txt
data="2013102100"
data1="${data:0:4}"
data2="${data:4:2}"
data3="${data:6:2}"
data4="${data:8:2}"
echo "$data1 $data2 $data3 $data4"
# Notice spaces are now removed as per your EDIT!!!
echo "$data1$data2$data3$data4" > /tmp/kuku.txt
cat < /tmp/kuku.txt
#for n in {1..99}
#do
#	data4="0$n"
#	echo "$data1 $data2 $data3 $data4"
#	echo "$data1$data2$data3$data4" > /tmp/kuku.txt
#	cat < /tmp/kuku.txt
#done
data4="04"
echo "$data1 $data2 $data3 $data4"
echo "$data1$data2$data3$data4" > /tmp/kuku.txt
cat < /tmp/kuku.txt
data4="100"
echo "$data1 $data2 $data3 $data4"
echo "$data1$data2$data3$data4" > /tmp/kuku.txt
cat < /tmp/kuku.txt

Results...

Last login: Thu Oct 10 19:35:31 on ttys000
AMIGA:barrywalker~> ./num.sh
2013 10 21 00
2013102100
2013 10 21 04
2013102104
2013 10 21 100
20131021100
AMIGA:barrywalker~> 

I got confused totally...... My number is in file kuku.txt
cat kuku.txt
->2013101005
According to my code it takes number from the file then compares with numbers and increment +1......But All I got from this code is 1!! Why????
I need to get 2013101006 only

n= sort /Users/Natalie/1/kuku.txt | tail -1
#n=2013080805
#echo "${n:0:4} ${n:4:2} ${n:6:2} ${n:8:2}"

fourthoct=${n:0:4}
thirdoct=${n:4:2}
secondoct=${n:6:2}
firstoct=${n:8:2}
echo $n


            if [ $((++firstoct)) -eq 101 ]
                   then
                  firstoct=00
                   if [ $((++secondoct)) -eq 32 ]
                        then

                        secondoct=0
                         if [ $((++thirdoct)) -eq 13 ]
                               then
                                thirdoct=0
                                   ((++fourthoct))
fi
fi
fi

echo $fourthoct$thirdoct$secondoct$firstoct
$ cat kuku.txt
2013101005
$ sh increm $(cat kuku.txt)
2013101006
$

(Please see post #14 for the code of increm shell script as well as for the comments ... this may save you tedious date calculations : indeed : what if the month has only 30 days or 28 days ... or if it's a leap year ?)

Add some :

echo $fourthoct 
echo $thirdoct 
echo $secondoct 
echo $firstoct

In your script to control if the values are correctly setup and if their values behave as you expect

I did. fourthoct 3oct 2oct 1oct gives nothing as well..... Even i said in my code that 1oct={n:8:2} etc.... I checked my n= sort /Users/yerlanrsaldin/1/kuku.txt | tail -1 it gives me 2013101005...but when I assign it to 1oct 2oct etc then here it does not work.... How i can get the value of the file in path in another way?

Please provide exactly the command line you've launched in the first run and in the second run.

By the way, the run i've tried with your code when i pass

2013080805

returns

201308086

Fyi you could use printf see :

$ i=6
$ echo $i
6
$ printf '%02d\n' $i
06
$

I found out what is probably wrong in my code. When i assign n=2013101005 instead of path in my code it works. But when I replace by path n=/Users/Natalie/1/kuku.txt (echo $n gives me 2013101005) then echo 1oct
echo 2oct ect gives me nothing. So i think
mine assign 1oct={n:8:2} 2oct {n:6:2} etc does not work here....