need a shell script to convert big endian to little endian
Asked Answered
D

6

10

I need a shell script program to print the hexadecimal number from big endian to little endian

For example

  • Input: my virtual address = 00d66d7e
  • Output: 7e6dd600

How can I can I create this in a bash script?

Dupre answered 10/3, 2014 at 9:52 Comment(4)
looks like simple string manipulation.Satiny
Why don't show what you have tried? Stackoverflow is not for request. It is for answering questionsArchiepiscopate
Also, what does C relate to the shell? And what shell?Archiepiscopate
Possible duplicate of Command-line to reverse byte order/change endianess. Also see How to reverse the byte order of an 8-byte string in Perl?.Lennon
S
15

For 32 bit addresses, assuming it's zero padded:

v=00d66d7e 
echo ${v:6:2}${v:4:2}${v:2:2}${v:0:2}
# 7e6dd600
Satiny answered 10/3, 2014 at 10:5 Comment(0)
F
17

Just had to do this... but from decimal to little endian.. adapting that here:

echo 00d66d7e | tac -rs .. | echo "$(tr -d '\n')"

achieves the desired result, for arbitrarily sized hexadecimal representations of unsigned integers.

(h/t 'tac -rs' MestreLion, very nice!)

Fraud answered 19/9, 2016 at 3:21 Comment(3)
very clever solution, +1! May I suggest an improvement? tac, or at least GNU tac, accepts a regex as separator, so grep is not needed: echo "AABBCC" | tac -rs ..Keirakeiser
note, the unusual echo "$()" mechanism it basically just to get a newline at the end... could replace with { tr -d '\n'; echo; } or some such.Fraud
Very nice solution. I'd prefer echo -n 00d66d7e | tac -rs .. ; echo but that's just taste I guess.Agricola
S
15

For 32 bit addresses, assuming it's zero padded:

v=00d66d7e 
echo ${v:6:2}${v:4:2}${v:2:2}${v:0:2}
# 7e6dd600
Satiny answered 10/3, 2014 at 10:5 Comment(0)
C
13

Based on Karoly's answer you could use the following script, reading an argument or piped input:

#!/bin/bash

# check 1st arg or stdin
if [ $# -ne 1 ]; then
  if [ -t 0 ]; then
    exit
  else
    v=`cat /dev/stdin`
  fi
else
  v=$1
fi

i=${#v}

while [ $i -gt 0 ]
do
    i=$[$i-2]
    echo -n ${v:$i:2}
done

echo

For e.g. you could save this script as endian.sh and make it executable with:

chmod u+x endian.sh

Then:

echo 00d66d7e | ./endian.sh

gives you:

7e6dd600

For a different length string:

echo d76f411475428afc90947ee320 | ./endian.sh

result would be:

20e37e9490fc8a427514416fd7

#Update: Modified the script to accept the input either as an argument or from stdin, addressing Freewind's request. So now:

./endian.sh d76f411475428afc90947ee320

also works and gives you:

20e37e9490fc8a427514416fd7
Challenging answered 17/12, 2015 at 5:7 Comment(3)
How to change the script to make it work with ./endian.sh d76f411475428afc90947ee320? Thanks!Spada
@Spada my answer addresses your requestTrace
Modified the script to make it work with an argument as well. @SpadaChallenging
T
4

This works for dash (and many other shells) :

v=0x12345678
v2=$(( (v<<8 & 0xff00ff00) | (v>>8 & 0xff00ff) ))
v2=$(( (v2<<16 & 0xffff0000) | v2>>16 ))
printf '0x%08x\n' $v2

Result should be "0x78563412"

${v:6:2} is for bash.
Trophoblast answered 4/8, 2014 at 11:25 Comment(0)
T
2

In response to Freewind's comment request and building off of hutheano's great answer, I wrote my own bash script and I include a condensed version below. The full script can be downloaded here.

The following implementation accounts for odd length strings, 0x or \x prefixes, and multiple output formats and can be used like the following:

$ be2le d76f411475428afc90947ee320 0xaaff 0xffa '\x3'
20e37e9490fc8a427514416fd7
0xffaa
0xfa0f
\x03

be2le bash script

#!/bin/bash

args=()

format=preserve
delimiter="\n"
nonewline=false
join=false
strip=false

while (( "$#" )); do
    case "$1" in
        -h|--help) usage;;
        -f) format=$2; shift 2;;
        --format=*) format="${1#*=}"; shift;;
        -d) delimiter=$2; shift 2;;
        --delimiter=*) delimiter="${1#*=}"; shift;;
        -n|--no-newline) nonewline=true; shift;;
        -j|--join) join=true; shift;;
        -s|--strip-null) strip=true; shift;;
        -*|--*) echo "Error: unsupported flag $1 specified"; exit 1;;
        *) args=( "${args[@]}" "$1" ); shift;;
    esac
done

case "$format" in
    preserve);;
    int) prefix="0x";;
    char) prefix="\x";; 
    raw) ;;
    *) echo "Error: unsupported format $format"; exit 1;;
esac

n=0
parts=()
for arg in ${args[@]}; do

    digest=""
    prefix=""

    # remove prefix if string begins with "0x"
    if [[ $arg =~ ^[0\\]x ]]; then
        if [ "$format" == "preserve" ]; then
            prefix=${arg:0:2}
        fi
        arg=${arg:2}
    fi

    # zero-pad if string has odd length
    if [ $[${#arg} % 2] != 0 ]; then
        arg="0$arg"
    fi

    part=""
    i=${#arg}
    while [ $i -gt 0 ]; do
        i=$[$i-2]
        byte=${arg:$i:2}
        if [ $strip == true ] && [ -z "$part" ] && [ $byte == "00" ]; then
            continue
        fi
        case "$format" in
            int) part="$part"'0x'"$byte ";;
            char) part="$part\x$byte";;
            raw) part="$part$(printf "%b" "\x$byte")";;
            *) part="$part$byte";;
        esac
    done

    digest="$prefix$digest$part"

    parts=( "${parts[@]}" "$digest" )
    n=$[$n+1]

done

if [ $join == true ]; then
    case "$format" in
        *) printf "%s" "${parts[@]}";;
    esac
else
    i=0
    for part in "${parts[@]}"; do
        if [[ $(($i + 1)) < $n ]]; then
            printf "%s$delimiter" "$part"
        else
            printf "%s" "$part"
        fi
        i=$(($i+1))
    done
fi

if [ $nonewline == false ]; then
    echo
fi
Trace answered 17/4, 2019 at 15:36 Comment(0)
G
0

This script is for flipping 16 bit data.

#!/bin/bash

if [ -t 0 ]; then exit; fi

data=`cat /dev/stdin | od -An -vtx1 | tr -d ' ' | tr -d '\n'`
length=${#data}

i=0
while [ $i -lt $length ]; do
    echo -n -e "\x${data:$[$i+2]:2}"
    echo -n -e "\x${data:$[$i]:2}"
    i=$[$i+4]
done
Gupta answered 1/7, 2017 at 23:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.