Solved convert word to hex, oct, dec with echo?

hello, I am looking for a way to convert a word in hexa octa and decimal by the command echo and back again, in the example I only found printf.

Code:
st0="test"
for ((z=0; z<${#st0}; z++)); do a+=$(printf %0x \'${st0:$z:1}); done; st1=$a; unset a; unset z
echo $st1
for ((z=0; z<${#st1}; z+=2)); do a+=$(printf \\x${st1:$z:2}); done; st2=$a; unset a; unset z
echo $st2

greetings
 
Code:
echo  -n test |hexdump -e '1/1 "%02x"'
echo  -n test |hexdump -e '1/1 "%03o"'
echo  -n test |hexdump -e '1/1 "%03d"'
 
Code:
st0="test"
st1=$(echo -n $st0 | perl -ne 'print unpack "H*", $_')
st2=$(echo -n $st1 | perl -ne 'print pack "H*", $_') 
echo $st2
 
Thank you, but does someone know a possibility without an additional library?
Have only the deceleration and hex and dec or oct are missing here.

Code:
st1="74657374"
for ((z=0; z<${#st1}; z+=2)); do a+=$(echo -n -e \\x${st1:$z:2}); done; st2=$a; unset a; unset z
echo $st2
 
The following works with ksh:
Code:
hex()
{
    echo $1
}

dec()
{
    echo $((16#$1))
}

oct()
{
    typeset -i8 v=$((16#$1))
    echo ${v#*#}
}

st1="74657374"
for ((z=0; z<${#st1}; z+=2)); do a+=$(echo -n -e $(hex ${st1:$z:2}) " "); done; st2=$a; unset a; unset z
echo $st2
for ((z=0; z<${#st1}; z+=2)); do a+=$(echo -n -e $(dec ${st1:$z:2}) " "); done; st2=$a; unset a; unset z
echo $st2
for ((z=0; z<${#st1}; z+=2)); do a+=$(echo -n -e $(oct ${st1:$z:2}) " "); done; st2=$a; unset a; unset z
echo $st2
 
Would oct look like as oneliner, what does Typeset -I8?

Code:
st1="74657374"
for ((z=0; z<${#st1}; z+=2)); do y=$(echo -n -e $((16#${st1:$z:2})) " "); a+=$(echo ${y#*#}); done; st2=$a; unset a; unset z
echo $st2

And how can I convert it back?
 
Would oct look like as oneliner, what does Typeset -I8?
I should point out that I have been using ksh93.

The man page for ksh (any version) says for "typeset":
Code:
-i[n]  Declares vname to be represented internally as integer.
       The right hand side of an assignment is evaluated as an
       arithmetic expression when assigning to an integer.  If n
       is non-zero, it defines the output arithmetic base,
       otherwise the output base will be ten.
So, it's declaring an integer with an octal base, which when output will always have a "8#" prefix.
The "${v#*#}" is stripping everything up to and including the "#" from "$v".

Putting the functions inline:
Code:
st1="74657374"
for ((z=0; z<${#st1}; z+=2)); do a+=$(echo -n -e $(echo ${st1:$z:2}) " "); done; st2=$a; unset a; unset z
echo $st2
for ((z=0; z<${#st1}; z+=2)); do a+=$(echo -n -e $((16#${st1:$z:2})) " "); done; st2=$a; unset a; unset z
echo $st2
typeset -i8 v
for ((z=0; z<${#st1}; z+=2)); do; v=$((16#${st1:$z:2})); a+=$(echo -n -e ${v#*#} " "); done; st2=$a; unset a; unset z
echo $st2
And how can I convert it back?
Using the shell for this sort of thing is torture. I would probably use an array initialised with the ASCII character set (or whatever character set you want).
You could then use the decimal value of each character to index the array... but it's Friday night where I am, so it's time for a break.
 
here is proof of concept convertion POSIX sh WITHOUT any external command
it only works for ascii codes 33-126 (no non-printable,no space, no UTF, no SHEEP)
Code:
#!/bin/sh
A="! \" # $ % & ' ( ) \* + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ 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 { | } \~";
B="21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f"
C="041 042 043 044 045 046 047 050 051 052 053 054 055 056 057 060 061 062 063 064 065 066 067 070 071 072 073 074 075 076 077 100 101 102 103 104 105 106 107 110 111 112 113 114 115 116 117 120 121 122 123 124 125 126 127 130 131 132 133 134 135 136 137 140 141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160 161 162 163 164 165 166 167 170 171 172 173 174 175 176 177"

first_char()
{
local a b
a=$1
[ "${#a}" -eq 1 ] && echo $a && return
n=${#a}
b=""
while [ $n -ne 1 ]
do
b="${b}?"
n=$(($n-1))
done
a=${a%$b}
echo "$a"
}

bsearch()
{
local mid piv fnd
AR="$1"
lft=$3
rgt=$4
src="$2"

mid=$(($lft+$rgt))
mid=$(($mid/2))
[ $lft -gt $rgt ] && mid=$(($mid+1))

piv=$(getAt "$AR" $mid)
[ "${#piv}" -eq 2 ] && piv="${piv#\\}"
 [ "$piv" = "$src" -o "$piv" = "$src" ] && echo $mid && return
 [ "$piv" \> "$src" ] && bsearch "$AR" "$src" $lft $(($mid-1))
 [ "$piv" \< "$src" ] && bsearch "$AR" "$src" $(($mid+1)) $rgt
}

acode()
{
#[ "$1" = " " ] && echo 32 && return
bsearch "$A" "$1" 33 127
}

hcode()
{
bsearch "$B" "$1" 33 127
}

ocode()
{
bsearch "$C" "$1" 33 127
}
getAt()
{
ind=$2
ind=$(($ind-32))
set -- $1
eval V=\${${ind}}
echo "$V"
}
test="the-quick-brown-fox-jumped-over-the-lazy-brown-dog"
echo "INPUT $test"
dec=""
hex=""
oct=""
while [ "$test" != "" ]
 do
 c=$(first_char "$test")
 bec=$(acode "$c")
# echo $bec
 h=$(getAt "$B" $bec)
 o=$(getAt "$C" $bec)
 dec="${dec} ${bec}"
 hex="${hex} ${h}"
 oct="${oct} ${o}"
 test=${test#?}
done
echo D: $dec
echo H: $hex
echo O: $oct
#from decimal
echo "TESTING decimal"
str=""
for b in $dec
do
har=$(getAt "$A" $b)
str="$str$har"
done
echo $str

#from hex
echo "TESTING hex"
str=""
for b in $hex
do
b=$(hcode $b)
har=$(getAt "$A" $b)
str="$str$har"
done
echo $str

#from oct
echo "TESTING oct"
str=""
for b in $oct
do
b=$(ocode $b)
har=$(getAt "$A" $b)
str="$str$har"
done
echo $str
 
I made good on the suggestion to use an ASCII lookup table.
This is another solution using the OP's original dissection of the hex string and ksh93 only:
Code:
typeset -a ASCII=(
     $'\c@' $'\cA' $'\cB' $'\cC' $'\cD' $'\cE' $'\cF' $'\cG'
     $'\cH' $'\cI' $'\cJ' $'\cK' $'\cL' $'\cM' $'\cN' $'\cO'
     $'\cP' $'\cQ' $'\cR' $'\cS' $'\cT' $'\cU' $'\cV' $'\cW'
     $'\cX' $'\cY' $'\cZ' $'\c[' $'\c\\' $'\c]' $'\c^' $'\c_'
     ' ' '!' '"' '#' '$' '%' '&' "'"
     '(' ')' '*' '+' ',' '-' '.' '/'
     '0' '1' '2' '3' '4' '5' '6' '7'
     '8' '9' ':' ';' '<' '=' '>' '?'
     '@' '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' '{' '|' '}' '~'  "\0177"
)

st1="74657374"

# Hexidecimal
unset a
for ((z=0; z<${#st1}; z+=2))
do
    a+=$(echo -n -e $(echo ${st1:$z:2}) " ")
done
st2=$a
echo $st2
IFS=' ' read -A hexs <<< $st2
for hc in ${hexs[@]}
do
    echo -n ${ASCII[16#"$hc"]} " "
done
echo

# Decimal
unset a
for ((z=0; z<${#st1}; z+=2))
do
    a+=$(echo -n -e $((16#${st1:$z:2})) " ")
done
st2=$a
echo $st2
IFS=' ' read -A decimals <<< $st2
for dc in ${decimals[@]}
do
    echo -n ${ASCII["$dc"]} " "
done
echo

# Octal
typeset -i8 v
unset a
for ((z=0; z<${#st1}; z+=2))
do
    v=$((16#${st1:$z:2}))
    a+=$(echo -n -e ${v#*#} " ")
done
st2=$a
echo $st2
IFS=' ' read -A octals <<< $st2
for oc in ${octals[@]}
do
    echo -n ${ASCII["8#$oc"]} " "
done
echo
This is a brilliant example of a really bad way to do something.
When ever I find myself writing anything as cryptic and arcane as this with any shell, it's time to down tools and switch to perl...

Edit: I have just realised that the shell is censoring some of the special characters.
e.g. If I put a BEL (0x07) in the string, everything works as expected, but a HT (0x09) does not print.
So this solution really only works reliably for the conventional printable characters.
Shell is the wrong tool for this task, so I'm not intending to persevere...
 
Both work very well, but I changed the first script and can't convert spaces.

Code:
A="\  \! \" # $ % & ' ( ) \* + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ 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 { | } \~";
B="20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f"
C="040 041 042 043 044 045 046 047 050 051 052 053 054 055 056 057 060 061 062 063 064 065 066 067 070 071 072 073 074 075 076 077 100 101 102 103 104 105 106 107 110 111 112 113 114 115 116 117 120 121 122 123 124 125 126 127 130 131 132 133 134 135 136 137 140 141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160 161 162 163 164 165 166 167 170 171 172 173 174 175 176 177"

str="te st space error!"
dec=""
hex=""
oct=""
while [ "$str" != "" ]; do
    z=$str
    [ "${#z}" -eq 1 ] && echo $z && true
    y=${#z}; x=""
    while [ $y -ne 1 ]; do x="${x}?"; y=$(($y-1)); done
    z=${z%$x}
    
    AR="$A"
    src="$z"
    lft=33
    rgt=127

    while [[ "$piv" != "$src" || "$piv" != "$src" ]]; do

        mid=$(($lft+$rgt))
        mid=$(($mid/2))
        [ $lft -gt $rgt ] && mid=$(($mid+1))
    
        ind=$mid
        ind=$(($ind-32))
        set -- $AR
        eval piv=\${${ind}}
        [ "${#piv}" -eq 2 ] && piv="${piv#\\}"
        [ "$piv" = "$src" -o "$piv" = "$src" ] && bec=$mid && break
        [ "$piv" \> "$src" ] && rgt=$(($mid-1)) && continue
        [ "$piv" \< "$src" ] && lft=$(($mid+1)) && continue
    done
        
    ind=$bec
    ind=$(($ind-32))
    set -- $B
    eval h=\${${ind}}
        
    ind=$bec
    ind=$(($ind-32))
    set -- $C
    eval o=\${${ind}}

    dec="${dec} ${bec}"
    hex="${hex} ${h}"
    oct="${oct} ${o}"
    str=${str#?}
done
echo $dec
echo $hex
echo $oct
 
set -- does not work for space ' ' even when escaped
if your target is bash anyway you can use arrays and get rid of the set -- altogether
also in my example i omitted space and used 33-127, you need 32-127
also ind=ind-32 should become ind-31
but again you can use arrays in bash
even in posix shell you can use VAR_20 to VAR_127 with some more evals and escape/evade the set --
 
Can you help me with that? I don't know how to integrate the array. Have your example also for encode/decode too but this does not leave me in peace.
 
Code:
ind=32
for f in 2 3 4 5 6 7
 do for g in 0 1 2 3 4 5 6 7 8 9 a b c d e f
  do
  A[$ind]=$(echo -e "\x$f$g")
  H[$ind]=\x$f$g
  O[$ind]=$(($ind/64))$(($(($ind/8))%8))$(($ind%8))
  echo "${A[$ind]} ${H[$ind]} ${O[$ind]}"
  ind=$(($ind+1))
 
 done
 done
echo ${A[65]} ${A[32]} ${A[33]}
 
Back
Top