Заменить шестнадцатеричный символ другим случайным символом (возможно awk?)

#bash #awk #replace #hexdump #xxd

#bash #awk #заменить #шестнадцатеричный дамп #xxd

Вопрос:

у меня есть 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 мастер 🙂 Спасибо.

Комментарии:

1. Извините, не ясно. Можете ли вы уточнить, что вы пытаетесь сделать?

2. Я пытаюсь изменить одну цифру mac-адреса. Мне нужна эта конкретная позиция, и мне нужно заменить ее другим случайным шестнадцатеричным символом. И мне нужно сделать это с помощью awk, если возможно, вместо использования так, как я уже это сделал. Выполните poc, и вы увидите

3. Изменение mac-адреса в указанной позиции — это нормально, но является ли генерация случайной строки путем вызова xxd также обязательным требованием?

4. Требуется другой символ… но я пытаюсь избежать использования xxd

Ответ №1:

Что-то подобное может работать с начальным значением из $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($4, 2, 1))
   $4 = substr($4, 1, 1) s
} 1' <<< "$mac"
  

 00:00:00:03:00:00
  

Внутри цикла while мы продолжаем до тех пор, пока шестнадцатеричная цифра не будет равна substr($4, 2, 1) какому 2-му символу 4-го столбца.

Комментарии:

1. Подождите … это не работает, если вы установили mac как «11:11:11:11:11:11», это не печать mac с измененным только одним символом… он печатает «11:11:11:03:11:11» но это должно быть «11:11:11:13:11:11»

Ответ №2:

Вам не нужен xxd or hexdump . urandom также сгенерирует nubmers, которые соответствуют кодировкам цифр и букв, используемых для представления шестнадцатеричных чисел, поэтому вы можете просто использовать

 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 данные в его stdin без необходимости использовать echo или что-то в этом роде.

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

Хитрость здесь заключается в добавлении случайного числа от 1 до 15 (оба включительно) к изменяемой цифре. Если в итоге получается число больше 15, мы выполняем обход, используя оператор modulo % ( 16 становится 0 , 17 становится 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}"
  

«Однострочная» версия:

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

Комментарии:

1. @OscarAkaElvis забыл об одном требовании. Подождите, пока я отредактирую.

2. Вам нужно добавить проверку того, что новая цифра отличается от исходной

3. Да, иногда он печатает 00:00:00:00:00:00 чего я хочу избежать … в этом случае мне нужна цифра, отличная от исходного «0»

4. srand() не очень случайный. Должно быть лучшее начальное значение, чем время суток. в противном случае несколько вызовов в быстрой последовательности получат один и тот же результат

5. @OscarAkaElvis Исправил проблему.

Ответ №3:

в bash встроен printf и функция random (если вы ей доверяете):

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

Вызвать с символом, который должен быть заменен в качестве аргумента.

Комментарии:

1. Это может быть… но я подожду какого-нибудь решения oneliner, если это возможно. Спасибо, я уже проголосовал за

Ответ №4:

Другой 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
  

или oneliner:

 $ awk -v n=11 -v s=$RANDOM 'BEGIN{FS=OFS=""}{srand(s);while((r=sprintf("%x",rand()*16))==$n);$n=r}1' <<< $mac
  

Комментарии:

1. да, еще одно отличное решение с использованием awk. поддержано, спасибо

Ответ №5:

 $ mac="00:00:00:00:00:00"
$ awk -v m="$mac" -v p=11 'BEGIN{srand(); printf "%s%X%sn", 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%sn", 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