0

Is there a way in BASH to convert an integer to a shortened alphanumeric string?

If I start, let's say with var=20171019194210. I would like to get something like the following.

echo "$var" | encoding
a4f5e6g

And then:

echo "$var" | decoding
20171019194210

I found something in Python on Stackoverflow; but, if possible, I would prefer to use BASH with any combination of GNU tools like awk to do it.

I am trying to create a unique ID for files by creating a timestamp as follows.

date +"%Y%m%d%H%M%S"

I then include this timestamp in the file name to identify the file on the system without needing to use a whole filename or to be able to identify the file without the rest of the file name.

I would now like to shorten or encode this integer to make it more usable in terms of its length, but in the same way having the possibility to recalculate the timestamp value.

  • What is it exactly that you're trying to do? Your question is unclear and devoid of context, and also somewhat circular - you want to store an integer as a string so that you can use it later as in integer? – DopeGhoti Oct 19 '17 at 17:53
  • @DopeGhoti sorry for being unclear, I rewrote the question and added the context. THX for the feedback! – nath Oct 19 '17 at 18:22
1

This is in bash, so it will be slow. It maps 2 numbers to 1 character. It uses the base64 alphabet so it can only accomodate numbers between 0 and 63 -- it's OK for hours, minutes, seconds, days and months, but will stop working in 2064. Extend the map with more characters to extend it.

declare -a map=(
    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
    a b c d e f g h i j k l m n o p q r s t u v w x y z 
    0 1 2 3 4 5 6 7 8 9 + /
)

declare -A revmap
for ((i=0; i<${#map[@]}; i++)); do revmap[${map[i]}]=$(printf "%02d" $i); done

encode() { 
    local i result=""
    for ((i=0; $i < ${#1}; i+=2)); do 
        # specifies base 10 numbers to prevent attempted interpretation
        # of invalid octal numbers 08,09
        result+=${map[10#${1:i:2}]:-"?"}
    done
    echo "$result"
}

decode() { 
    local i result=""
    for ((i=0; i<${#1}; i++)); do 
        result+=${revmap[${1:i:1}]:-"??"}
    done
    echo "$result"
}

encode 20171019194210              # => URKTTqK
decode $(encode 20171019194210)    # => 20171019194210

encode 20671019194210              # => U?KTTqK
# .......^^
decode "$(encode 20671019194210)"  # => 20??1019194210
1

How much shorter do you expect? Using hexadecimal representation will make it 2 chars less for the given number. For a longer number it may save more.

LONGER=20171019194210                                #compare: 
SHORTER=$(printf "%X\n" $LONGER)                     #12586E6F0F62
RESTORED=$(echo "obase=10; ibase=16; $SHORTER" | bc) #20171019194210
  • thanks for your answer, but I expected it to be about half the size of characters. – nath Oct 19 '17 at 18:34
  • 1
    After you extended your question.. I guess that's exactly your case stackoverflow.com/a/23975915/439650 with it you can pack a timestamp within timerange of 280 years into 5 chars ( if neglecting seconds ) – Tagwint Oct 19 '17 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.