用不同的随机字符替换十六进制字符(awk 可能吗?)

Replace hex char by a different random one (awk possible?)

有一个 mac 地址,我只需要用一个不同的随机字符(它必须与原始字符不同)替换一个十六进制字符(一个在非常特定的位置)。我使用 xxd 以这种方式完成了它并且它有效:

#!/bin/bash
mac="00:00:00:00:00:00" #This is a PoC mac address obviously :)
different_mac_digit=$(xxd -p -u -l 100 < /dev/urandom  | sed "s/${mac:10:1}//g" | head -c 1)
changed_mac=${mac::10}${different_mac_digit}${mac:11:6}
echo "${changed_mac}" #This echo stuff like 00:00:00:0F:00:00

我的脚本的问题是使用 xxd 意味着另一个依赖项...我想避免它(并非所有 Linux 默认都包含它)。我有另一个使用 hexdump 命令的解决方法,但使用它我处于同一阶段......但我的脚本已经具有强制性 awk 依赖性,所以......可以使用 awk?我需要一位 awk 大师 :) 谢谢。

bash 有内置的 printf 和一个随机函数(如果你相信它的话):

different_mac_digit() {
    new=
    while [[ $new =  ]]; do
        new=$( printf "%X" $(( RANDOM%16 )) )
    done
    echo $new
}

以要替换的字符作为参数调用。

您不需要 xxdhexdumpurandom 还将生成与用于表示十六进制数的数字和字母的编码相匹配的数字,因此您可以只使用

old="${mac:10:1}"
different_mac_digit=$(tr -dc 0-9A-F < /dev/urandom | tr -d "$old" | head -c1)

当然,您也可以用 awk 脚本替换整个脚本。以下 GNU awk 脚本将每行的第 11 个符号替换为与旧符号不同的随机十六进制符号。使用 <<< macaddress 我们可以将 macaddress 提供给它的标准输入,而不必使用 echo 或类似的东西。

awk 'BEGIN { srand(); pos=11 } {
  old=strtonum("0x" substr([=11=],pos,1))
  new=(old + 1 + int(rand()*15)) % 16
  print substr([=11=],1,pos-1) sprintf("%X",new) substr([=11=],pos+1)
}' <<< 00:00:00:00:00:00

这里的技巧是在要修改的数字上添加一个介于 1 和 15(包括两者)之间的随机数。如果我们最终得到一个大于 15 的数字,我们使用模运算符 % 环绕(16 变为 017 变为 1,依此类推).这样得到的数字保证与旧数字不同。

但是,如果完全写在 bash 中,相同的方法会更短。

mac="00:00:00:00:00:00"
old="${mac:10:1}"
(( new=(16#"$old" + 1 + RANDOM % 15) % 16 ))
printf %s%X%s\n "${mac::10}" "$new" "${mac:11}"

"One-liner"版本:

mac=00:00:00:00:00:00
printf %s%X%s\n "${mac::10}" "$(((16#${mac:10:1}+1+RANDOM%15)%16))" "${mac:11}"

这样的事情可能适用于 $RANDOM:

的种子值
mac="00:00:00:00:00:00"
awk -v seed=$RANDOM 'BEGIN{ FS=OFS=":"; srand(seed) } {
   s="0"
   while ((s = sprintf("%x", rand() * 16)) == substr(, 2, 1))
    = substr(, 1, 1) s
} 1' <<< "$mac"

00:00:00:03:00:00

在 while 循环中,我们继续直到十六进制数字不等于 substr(, 2, 1) 第 4 列的第 2 个字符。

另一个 awk:

$ awk -v n=11 -v s=$RANDOM '                # set n to char # you want to replace
BEGIN { FS=OFS="" }{                        # each char is a field
    srand(s)                                
    while((r=sprintf("%x",rand()*16))==$n);  
    $n=r
}1' <<< $mac

输出:

00:00:00:07:00:00

或一线:

$ awk -v n=11 -v s=$RANDOM 'BEGIN{FS=OFS=""}{srand(s);while((r=sprintf("%x",rand()*16))==$n);$n=r}1' <<< $mac
$ mac="00:00:00:00:00:00"
$ awk -v m="$mac" -v p=11 'BEGIN{srand(); printf "%s%X%s\n", substr(m,1,p-1), int(rand()*15-1), substr(m,p+1)}'
00:00:00:01:00:00
$ awk -v m="$mac" -v p=11 'BEGIN{srand(); printf "%s%X%s\n", substr(m,1,p-1), int(rand()*15-1), substr(m,p+1)}'
00:00:00:0D:00:00

并确保您得到的数字与开始时不同:

$ awk -v mac="$mac" -v pos=11 'BEGIN {
    srand()
    new = old = toupper(substr(mac,pos,1))
    while (new==old) {
        new = sprintf("%X", int(rand()*15-1))
    }
    print substr(mac,1,pos-1) new substr(mac,pos+1)
}'
00:00:00:0D:00:00