I am a very newbie to bash scripting and am trying to write some code to parse and manipulate a file that I am working on.
I need to increment and decrement the minute of a time for a bunch of different times in a file. My problem happens when the time is for example 2:04 or 14:00.
File Example:
2:43
2:05
15:00
My current excerpt from my bash script is like this
for x in `cat $1`;
do minute_var=$(echo $x | cut -d: -f2);
incr_min=$(($minute_var + 1 | bc));
echo $incr_min;
done
Current Result:
44
6
1
Required Result:
44
06
01
Any suggestions
Use printf
:
incr_min=$(printf %02d $(($minute_var + 1 )) )
No that bc
is not needed if only integers are involved.
is this ok for your requirement?
kent$ echo "2:43
2:05
15:00"|awk -F: '{$2++;printf "%02d\n", $2}'
44
06
01
while IFS=: read hour min; do
printf "%02d\n" $((10#$min + 1))
done <<END
2:43
2:05
15:00
8:08
0:59
END
44
06
01
09
60
For the minute wrapping to the next hour, use a language with time functions, like gawk
awk -F: '{
time = mktime("1970 01 01 " $1 " " $2 " 00")
time += 60
print strftime("%M", time)
}'
perl -MTime::Piece -MTime::Seconds -nle '
$t = Time::Piece->strptime($_, "%H:%M");
print +($t + ONE_MINUTE)->strftime("%M");
'
UPDATED #2
There are some problems with your script. At first instead of `cat file`
you should use `<file`
or rather $(<file)
. One fork
and exec
call is spared as bash
simply opens the file. On the other hand calling cut
and bc
(and printf
) also not needed as bash
has internally the proper features. So you can spare some fork
s and exec
s again.
If the input file is large (greater then cca 32 KiB) then the for
-loop line can be too large to be processed by bash
so I suggest to use while
-loop instead and read the file line-by-line.
I could suggest something like this in pure bash
(applied Atle's substr solution):
while IFS=: read hr min; do
incr_min=$((1$min+1)); #Octal problem solved
echo ${incr_min: -2}; #Mind the space before -2!
#or with glennjackman's suggestion to use decimal base
#incr_min=0$((10#$min+1))
#echo ${incr_min: -2};
#or choroba's solution improved to set variable directly
#printf -v incr_min %02d $((10#$min+1))
#echo $incr_min
done <file
Input file
$ cat file
2:43
2:05
15:00
12:07
12:08
12:09
Output:
44
06
01
08
09
10
Maybe the printf -v
is the simplest as it puts the result to the variable in a single step.
Good question from tripleee
what should happen if the result is 60.
Use printf
to reformat the output to be zero-padded, 2-wide:
incr_min=$(printf %02d $incr_min)
Here's a solution that
- wraps the seconds from 59 to 0
- is fully POSIX compliant--no bashisms!
- doesn't need a single fork thus is extremely fast
$ cat x
2:43
2:05
2:08
2:09
15:00
15:59
$ while IFS=: read hr min; do
printf '%02d\n' $(((${min#0}+1)%60))
done < x
44
06
09
10
01
00
Try this:
for x in $(<$1); do
printf "%02d\n" $(((${x#*:}+1)%60));
done
Padding with 0, and getting two last characters:
for x in `cat $1`;
do minute_var=$(echo $x | cut -d: -f2);
incr_min=0$(($minute_var + 1 | bc));
echo ${incr_min: -2:2};
done