Can't Increment a 0-Padded Number Past 8 in Busybox Sh

Can't increment a 0-padded number past 8 in busybox sh

The problem is that leading 0s cause a number to be read as octal.

In bash, using $((10#$num)) will force decimal. Thus:

num=$(printf "%04d" "$((10#$num + 1))")

To work with busybox ash, you'll need to strip the 0s. One way to do this which will work even in busybox ash:

while [ "${num:0:1}" = 0 ]; do
num=${num:1}
done
num=$(printf '%04d' "$((num + 1))")

See the below transcript showing use (tested with ash from busybox v1.22.1):

$ num=0008
$ while [ "${num:0:1}" = 0 ]; do
> num=${num:1}
> done
$ num=$(printf '%04d' "$((num + 1))")
$ echo "$num"
0009

If your shell doesn't support even the baseline set of parameter expansions required by POSIX, you could instead end up using:

num=$(echo "$num" | sed -e 's/^0*//')
num=$(printf '%04d' "$(($num + 1))")

...though this would imply that your busybox was built with a shell other than ash, a decision I would strongly suggest reconsidering.

Linux shell script with file saving and sequential file naming

This will work if and only if your filenames are all identical except for the numeric part, and the numeric part is padded enough that they're all the same number of digits.

set -- *.jpg           # put the sorted list of names on argv
while [ $# -gt 1 ]; do # as long as there's more than one...
shift # ...pop something off the beginning...
done
num=${1#*snapfull} # trim the leading alpha part of the name
num=${num%.*} # trim the trailing numeric part of the name
printf -v num '%04d' "$((num + 1))" # increment the number and pad it out

wget http://127.0.0.1/snap.php -O "snapfull${num}.jpg"

Unexpected redirection while parsing string

maybe

tftp $TPTP_SERVER_IP -c "${line#*=}" "${line%=*}"

(that is — instead of the whole while body).

$ ash
$ line="asdasdsad=123123123123"
$ echo $line
asdasdsad=123123123123
$ echo ${line%=*}
asdasdsad
$ echo ${line#*=}
123123123123
$

How to compare two strings in dot separated version format in Bash?

Here is a pure Bash version that doesn't require any external utilities:

#!/bin/bash
vercomp () {
if [[ $1 == $2 ]]
then
return 0
fi
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++))
do
if [[ -z ${ver2[i]} ]]
then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]}))
then
return 1
fi
if ((10#${ver1[i]} < 10#${ver2[i]}))
then
return 2
fi
done
return 0
}

testvercomp () {
vercomp $1 $2
case $? in
0) op='=';;
1) op='>';;
2) op='<';;
esac
if [[ $op != $3 ]]
then
echo "FAIL: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'"
else
echo "Pass: '$1 $op $2'"
fi
}

# Run tests
# argument table format:
# testarg1 testarg2 expected_relationship
echo "The following tests should pass"
while read -r test
do
testvercomp $test
done << EOF
1 1 =
2.1 2.2 <
3.0.4.10 3.0.4.2 >
4.08 4.08.01 <
3.2.1.9.8144 3.2 >
3.2 3.2.1.9.8144 <
1.2 2.1 <
2.1 1.2 >
5.6.7 5.6.7 =
1.01.1 1.1.1 =
1.1.1 1.01.1 =
1 1.0 =
1.0 1 =
1.0.2.0 1.0.2 =
1..0 1.0 =
1.0 1..0 =
EOF

echo "The following test should fail (test the tester)"
testvercomp 1 1 '>'

Run the tests:

$ . ./vercomp
The following tests should pass
Pass: '1 = 1'
Pass: '2.1 < 2.2'
Pass: '3.0.4.10 > 3.0.4.2'
Pass: '4.08 < 4.08.01'
Pass: '3.2.1.9.8144 > 3.2'
Pass: '3.2 < 3.2.1.9.8144'
Pass: '1.2 < 2.1'
Pass: '2.1 > 1.2'
Pass: '5.6.7 = 5.6.7'
Pass: '1.01.1 = 1.1.1'
Pass: '1.1.1 = 1.01.1'
Pass: '1 = 1.0'
Pass: '1.0 = 1'
Pass: '1.0.2.0 = 1.0.2'
Pass: '1..0 = 1.0'
Pass: '1.0 = 1..0'
The following test should fail (test the tester)
FAIL: Expected '>', Actual '=', Arg1 '1', Arg2 '1'

Compare lines within a file in bash

Update to fix my former self-unknown line-ending error.

Use this, will work on both \r\n and \n line endings, output will end in \n:

awk -F, 'sub(/\r$/,"") ($(NF+1)=sprintf("%07d",a[$2]++))' OFS=, input.txt

Output:

12345678,Manoj,23,Developer,0000000
12345678,Manoj,34,Developer,0000001
12345678,Manoj,67,Developer,0000002
12345679,Vijay,12,Tester,0000000
12345679,Vijay,98,Tester,0000001
12345676,Samrat,100,Manager,0000000
12345676,Samrat,25,Manager,0000001
12345676,Samrat,28,Manager,0000002

I wrote like that is for conciseness, it's functionally equals to:

awk 'BEGIN{FS=OFS=","}{sub(/\r$/,"");$(NF+1)=sprintf("%07d",a[$2]++)}1' input.txt

If you have ruby installed:

ruby -aF, -pe 'BEGIN{a=Hash.new(-1)};sub(/\r?$/, "," + "%07d" % a[$F[1]]+=1)' input.txt

Same output.

Btw, if you want it starts with 19, you can use this (add 19+ to the value):

awk 'sub(/\r$/,"") ($(NF+1)=sprintf("%07d",19+a[$2]++))' FS=, OFS=, input.txt

Or this(initialize with 18):

ruby -aF, -pe 'BEGIN{a=Hash.new(18)};sub(/\r?$/, "," + "%07d" % a[$F[1]]+=1)' input.txt

These all used $2 (column 2) as the keys, since in your samples $1 and $2 are related, so use either one would work.



Related Topics



Leave a reply



Submit