incrementing a number in bash with leading 0

2019-06-12 14:00发布

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

8条回答
别忘想泡老子
2楼-- · 2019-06-12 14:38

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
查看更多
倾城 Initia
3楼-- · 2019-06-12 14:41

is this ok for your requirement?

kent$  echo "2:43
2:05
15:00"|awk -F: '{$2++;printf "%02d\n", $2}'
44
06
01
查看更多
狗以群分
4楼-- · 2019-06-12 14:47

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 forks and execs 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.

查看更多
叛逆
5楼-- · 2019-06-12 14:50

Try this:

for x in $(<$1); do
    printf "%02d\n" $(((${x#*:}+1)%60));
done
查看更多
相关推荐>>
6楼-- · 2019-06-12 14:51

Use printf to reformat the output to be zero-padded, 2-wide:

incr_min=$(printf %02d $incr_min)
查看更多
在下西门庆
7楼-- · 2019-06-12 14:52

Use printf:

incr_min=$(printf %02d $(($minute_var + 1 )) )

No that bc is not needed if only integers are involved.

查看更多
登录 后发表回答