Ответы:
Другие ответы маскируют фиксированное количество символов с самого начала с суффиксом открытого текста различной длины. Альтернативой было бы оставить фиксированное количество символов в виде открытого текста и изменить длину маскированной части. Я не знаю, какой из них более полезен, но вот другой выбор:
#!/bin/bash
mask() {
local n=3 # number of chars to leave
local a="${1:0:${#1}-n}" # take all but the last n chars
local b="${1:${#1}-n}" # take the final n chars
printf "%s%s\n" "${a//?/*}" "$b" # substitute a with asterisks
}
mask abcde
mask abcdefghijkl
Это печатает **cde
и *********jkl
.
Если хотите, вы также можете изменить n
короткие строки, чтобы убедиться, что большинство строк маскируется. Например, это обеспечит маскировку как минимум трех символов даже для коротких строк. (так abcde
-> ***de
и abc
-> ***
):
mask() {
local n=3
[[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
local a="${1:0:${#1}-n}"
local b="${1:${#1}-n}"
printf "%s%s\n" "${a//?/*}" "$b"
}
Одним из вариантов будет заставить себя использовать функцию вместо echo
, такую как:
obfuprint() {
if [ "${#1}" -ge 8 ]
then
printf '%s\n' "${1/????????/********}"
else
printf '%s\n' "${1//?/*}"
fi
}
Тогда вы можете позвонить obfuprint 'secretvalue'
и получить ********lue
(с завершающим переводом строки). Функция использует раскрытие параметров для поиска первых восьми символов переданного значения и заменяет их восемью звездочками. Если входящее значение короче восьми символов, все они заменяются звездочками. Спасибо ilkkachu за указание на мое первоначальное предположение о вводе восьми или более символов!
Вдохновленный гибким маскирующим ответом ilkkachu , я подумал, что было бы интересно добавить вариант, который случайным образом маскирует некоторый процент строки:
obfuprintperc () {
local perc=75 ## percent to obfuscate
local i=0
for((i=0; i < ${#1}; i++))
do
if [ $(( $RANDOM % 100 )) -lt "$perc" ]
then
printf '%s' '*'
else
printf '%s' "${1:i:1}"
fi
done
echo
}
Это зависит от BASH в $RANDOM
специальной переменной; он просто перебирает каждый символ ввода и решает, замаскировать ли этот символ или распечатать его. Пример вывода:
$ obfuprintperc 0123456789
0*****6*8*
$ obfuprintperc 0123456789
012***678*
$ obfuprintperc 0123456789
**********
$ obfuprintperc 0123456789
*****56***
$ obfuprintperc 0123456789
0*******8*
Вы могли бы попробовать трубопровод sed
. Например, чтобы заменить первые 8 символов строки звездочками, вы можете передать sed 's/^......../********/'
команду, например:
$ echo 'secretvalue' | sed 's/^......../********/'
********lue
Вы также можете определить функцию, которая делает это:
obsecho () { echo "$1" | sed 's/^......../*********/'; }
printf
болееecho
так , что вы не подлежат интерпретации данных , таких как \r
или\n
sed 's/^......../********/' <<< 'secretvalue'
bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo
.
zsh
Вариант , который маскирует три четверти текста:
mask() printf '%s\n' ${(l:$#1::*:)1:$#1*3/4}
Пример:
$ mask secretvalue
********lue
$ mask 12345678
******78
$ mask 1234
***4
Чтобы замаскировать первые 8 символов:
mask() printf '%s\n' ${(l:$#1::*:)1:8}
Чтобы замаскировать все, кроме последних 3 символов:
mask() printf '%s\n' ${(l:$#1::*:)1: -3}
Чтобы замаскировать случайное количество символов:
mask() printf '%s\n' ${(l:$#1::*:)1: RANDOM%$#1}
Еще один вариант в Bash, если вы не возражаете против одного простого, eval
вы можете сделать это с помощью пары printf
:
# example data
password=secretvalue
chars_to_show=3
# the real thing
eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
printf '%s\n' "${password: -chars_to_show}"
Но будь осторожен:
${#password}
меньше, чем${chars_to_show}
eval
может быть очень опасным с ненадежным вводом: здесь это может считаться безопасным, потому что его ввод поступает только из безопасных источников, то есть длины ${password}
и значения${chars_to_show}
Вот несколько игрушечных скриптов Bash, с которыми можно поиграть, чтобы показать, как объединить поиск в стиле регулярных выражений с подстановкой строк.
strip_str.sh
#!/usr/bin/env bash
_str="${1}"
_filter="${2:-'apl'}"
echo "${_str//[${_filter}]/}"
strip_str.sh 'apple-foo bar'
# -> e-foo br
strip_str.sh 'apple-foo bar' 'a'
# -> pple-foo br
privatize_str.sh
#!/usr/bin/env bash
_str="${1}"
_filter="${2:-'apl'}"
_replace="${3:-'*'}"
echo "${_str//[${_filter}]/${_replace}}"
privatize_str.sh 'apple-foo bar'
# -> ****e-foo b*r
restricted_str.sh
#!/usr/bin/env bash
_str="${1}"
_valid="${2:-'a-z'}"
_replace="${3:-''}"
echo "${_str//[^${_valid}]/${_replace}}"
restricted_str.sh 'apple-foo bar'
# -> applefoobar
Ключевые вынос
[a-z 0-9]
полностью действителен и удобен, как <search>
внутри ${_var_name//<search>/<replace>}
Bash^
в этом контексте является обратным или not
для регулярных поисковХотя я понимаю, что
printf
это лучше почти во всех случаях использования, приведенный выше код,echo
чтобы не слишком путать происходящее.
obfuscate_str.sh
#!/usr/bin/env bash
_str="${1}"
_start="${2:-6}"
_header="$(for i in {1..${_start}}; do echo -n '*'; done)"
echo "${_header}${_str:${_start}}"
obfuscate_str.sh 'apple-foo bar' 3
# -> ***le-foo bar