将文件中的十六进制值转换为十进制值的Shell脚本

vtwuwzda  于 2023-03-24  发布在  Shell
关注(0)|答案(6)|浏览(186)

我有一个名为text的文件,其中包含所有十六进制数字。我编写了以下代码将这些值转换为十进制:

for line in `cat text`; do

arp=$(echo "ibase=16; $line" | bc);echo $arp
     done

但它给了我以下错误:

(standard_in) 1: syntax error

我的输入文件包含一列十六进制值,例如:

428a2f98 
71374491 
b5c0fbcf
mrzz3bfm

mrzz3bfm1#

如果您的十六进制数是以下形式:

0x1
0x2
0x3
0x4
0x5
0x6
0x7
0x8
0x9
0xA
0xB
0xC
0xD
0xE
0xF

我的意思是前缀为0x,你可以用途:

while read line
do
     printf '%d\n' $line

done < text

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vfwfrxfs

vfwfrxfs2#

产生错误的不是bash,而是bc,它要求十六进制数字使用大写字母,而输入文件使用小写字母。
如果使用bash 4,可以使用${foo^^}$foo扩展为大写:

bc <<< "ibase=16; ${line^^}"

也可以使用tr

bc <<< "ibase=16; $(tr '[:lower:]' '[:upper:]' <<< "${line}")"
edqdpe6u

edqdpe6u3#

虽然这个问题的答案,当你不知道确切的位置的数字,这个sed oneliner可以帮助其他人寻求帮助,只有找到这个问题在网上:

$ cat file | sed 's/^/echo "/;s/(0x\(..\))/(\$(echo "ibase=16;\U\1\E"\|bc))/g;s/$/"/e'

说明:

  • s/^/echo "/在开始时添加echo "
  • s/(0x\(..\))/(\$(echo "ibase=16;\U\1\E"\|bc))/g需要进一步解释:

1.查找(0x..)模式。您可以根据自己的情况更改为^........

  • 创建子shell $(),其中十六进制模式\1bc处理
  • \U用于大写十六进制数字。\E停止大写。
  • s/$/"/e在末尾添加",并使用sh处理行

您可以在xmodmap输出上测试它,xmodmap输出十六进制字符作为修饰符,而xev将修饰符显示为小数。
希望它在其他用例中变得方便

eagi6jfj

eagi6jfj4#

while read line
do
    arp=$(echo "ibase=16; $line" | bc)
    echo $arp
done < in.txt

对于in.txt

1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
A0
A1
FF

这将打印:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
160
161
255
1yjd4xko

1yjd4xko5#

这个答案是基于albfan's answer和张贴出于同样的原因(其他人寻求帮助,只有在网上找到这个问题)。
我正在扩展它,以允许在包含反斜杠,反引号,双引号和美元符号的文件中进行替换。
这样,在未知输入上使用它也更安全,可以防止代码注入。

#!/bin/bash
cat $1 | sed -r 's/\\/\\\\/g;s/`/\\`/g;s/"/\\"/g;s/\$/\\$/g;s/0x([0-9A-Fa-f]+)/\$(echo "ibase=16;\U\1\E" \| bc)/g;s/^/echo "/;s/$/"/e'

要回答最初的问题,需要删除0x:

#!/bin/bash
cat $1 | sed -r 's/\\/\\\\/g;s/`/\\`/g;s/"/\\"/g;s/\$/\\$/g;s/([0-9A-Fa-f]+)/\$(echo "ibase=16;\U\1\E" \| bc)/g;s/^/echo "/;s/$/"/e'
简单演示:

输入线:

console.log("This is a number: 0xffffff")

中间体形式:

echo "console.log(\"This is a number: $(echo "ibase=16;FFFFFF" | bc)\")"

输出线:

console.log("This is a number: 16777215")
用法:

保存为hex-to-decimal.sh,chmod 555 hex-to-decimal.sh以使其可执行且不可编辑,并使用./hex-to-decimal.sh inputfilename > outputfilename运行
或者作为一行程序运行cat inputfilename | sed -r 's/\\/\\\\/g;s//\/g;s/"/\\"/g;s/\$/\\$/g;s/0x([0-9A-Fa-f]+)/\$(echo "ibase=16;\U\1\E" \| bc)/g;s/^/echo "/;s/$/"/e' > outputfilename

说明:

cat $1

  • 逐行列出输入文件的内容。

| sed -r

  • 对每行文本应用一系列转换(在本例中是替换和一次执行),并将结果打印到stdout。

s/\\/\\\\/g;

  • 在此行中的每个反斜杠之前放置一个反斜杠。

x1名6名1名x1名7名1名x1名8名1名

  • 对反引号、双引号和美元符号也这样做。

s/0x([0-9A-Fa-f]+)

  • 替换以0x开头并后跟十六进制数的任何内容。
  • 对于原始问题版本,0x被省略,它匹配任何有效的十六进制数。例如,导致fridge被替换为15ri13g14

/\$(echo "ibase=16;\U\1\E" \| bc)/g;

  • 将其替换为$(echo "ibase=16;+第一组大写(不含0x的数字)+" | bc)
  • \$(echo "ibase=16;\U\1\E" \| bc)
  • $(<command>)
  • 启动一个执行命令的子bash示例,并恢复执行,并将其替换为子bash示例的输出(在单引号('')字符串内无效)
  • \U\1\E
  • \U使后面的内容变为大写,\1是第一组(即[0-9A-Fa-f]+),\E使大写不适用于后面的内容。换句话说;十六进制数,大写。
  • echo "ibase=16;<hexadecimal number>" | bc
  • 使用bc命令将十六进制数(输入基数= 16)转换为十进制数(默认输出类型)。

s/^/echo "/;

  • echo "放在行的开头。

x1米30英寸1x

  • "放在该行的末尾并执行该行。
gab6jxml

gab6jxml6#

使用bc命令将十六进制值转换为十进制值是一种选择,但不是必需的。此外,bc可能看起来不必要地复杂。实际上,Bash提供了更简单的替代方案,如$((...))语法或$(printf "%d" "..."),可以产生相同的结果。

使用$((...))

$ cat file | sed -Ee 's@^@echo "@' \
  -e 's_\b0x[0-9A-Fa-f]+_\$((&))_g' \
  -e 's/$/"/e'

使用$(printf "%d" "...")

$ cat file | sed -Ee 's@^@echo "@' \
  -e 's_\b0x[0-9A-Fa-f]+_\$(printf "%d" &)_g' \
  -e 's/$/"/e'

说明:

-E标志

  • 用于扩展正则表达式。

-e标志

  • 用于将脚本添加到sed命令。
  • 这与使用;相同,;用于添加多个sed脚本。
  • 使用e标志更容易阅读,为什么不呢?

s@^@echo "@

  • ^表示每行的开始。
  • 它匹配一行的开头并插入echo "

s_\b0x[0-9A-Fa-f]+_\$((&))_g &&
s_\b0x[0-9A-Fa-f]+_\$(printf "%d" &)_g

  • \b用于字边界,因此它只匹配十六进制值

这到底是什么意思
所以,我有JavaScript和Python脚本,其中包括包含十六进制值的变量和函数,例如变量_0x371ac6。使用\b确保我们只替换十六进制值。

  • 0x[0-9A-Fa-f]+用于匹配十六进制值。
  • \$((&))用于将匹配的十六进制值替换为$((hexVal))
  • \$(printf "%d" &)用于将匹配的十六进制值替换为$(printf "%d" hexVal)

&是整个匹配或匹配的第0组。
可以使用\0代替&
s/$/"/e

  • $表示每行的结束。
  • 它匹配一行的结尾并插入"

/e用于将每行作为sh命令运行。

相关问题