Respostas:
As outras respostas ocultam uma quantidade fixa de caracteres desde o início, com o sufixo de texto sem formatação variando em tamanho. Uma alternativa seria deixar uma quantidade fixa de caracteres em texto simples e variar o comprimento da parte mascarada. Não sei qual é mais útil, mas aqui está a outra opção:
#!/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
Isso imprime **cde
e *********jkl
.
Se desejar, você também pode modificar n
as strings curtas para garantir que a maioria das strings seja mascarada. Por exemplo, isso garantiria que pelo menos três caracteres sejam mascarados, mesmo para seqüências curtas. (então abcde
-> ***de
e 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"
}
Uma opção seria forçar-se a usar uma função em vez de echo
, como:
obfuprint() {
if [ "${#1}" -ge 8 ]
then
printf '%s\n' "${1/????????/********}"
else
printf '%s\n' "${1//?/*}"
fi
}
Em seguida, você pode ligar obfuprint 'secretvalue'
e receber ********lue
(com uma nova linha à direita). A função usa a expansão de parâmetro para procurar os oito primeiros caracteres do valor passado e os substitui por oito asteriscos. Se o valor recebido for menor que oito caracteres, todos serão substituídos por asteriscos. Obrigado a ilkkachu por apontar minha suposição inicial de oito ou mais entradas de caracteres!
Inspirado pela resposta flexível de mascaramento do ilkkachu , achei interessante adicionar uma variação que mascara aleatoriamente uma porcentagem da string:
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
}
Isso depende da $RANDOM
variável especial do bash ; ele simplesmente percorre cada caractere da entrada e decide se deve mascará-lo ou imprimi-lo. Saída de amostra:
$ obfuprintperc 0123456789
0*****6*8*
$ obfuprintperc 0123456789
012***678*
$ obfuprintperc 0123456789
**********
$ obfuprintperc 0123456789
*****56***
$ obfuprintperc 0123456789
0*******8*
Você pode tentar canalizar para sed
. Por exemplo, para substituir os 8 primeiros caracteres de uma string por asteriscos, você pode canalizar para o sed 's/^......../********/'
comando, por exemplo:
$ echo 'secretvalue' | sed 's/^......../********/'
********lue
Você também pode definir uma função que faça isso:
obsecho () { echo "$1" | sed 's/^......../*********/'; }
sed 's/^......../********/' <<< 'secretvalue'
bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo
.
Uma zsh
variante que mascara três quartos do texto:
mask() printf '%s\n' ${(l:$#1::*:)1:$#1*3/4}
Exemplo:
$ mask secretvalue
********lue
$ mask 12345678
******78
$ mask 1234
***4
Para mascarar os 8 primeiros caracteres:
mask() printf '%s\n' ${(l:$#1::*:)1:8}
Para mascarar todos, exceto os últimos 3 caracteres:
mask() printf '%s\n' ${(l:$#1::*:)1: -3}
Para mascarar um número aleatório de caracteres:
mask() printf '%s\n' ${(l:$#1::*:)1: RANDOM%$#1}
Outra opção no Bash, se você não se importa com um simples, eval
pode fazê-lo com um par de 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}"
Mas tenha cuidado:
${#password}
for menor que${chars_to_show}
eval
pode ser muito perigoso com entradas não confiáveis: aqui pode ser considerada segura porque sua entrada vem apenas de fontes seguras, ou seja, o comprimento ${password}
e o valor de${chars_to_show}
Aqui estão alguns scripts Bash de brinquedo para brincar, que mostram como combinar pesquisa do tipo regex com substituição de string.
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
Principais tópicos
[a-z 0-9]
é totalmente válido e útil, como <search>
dentro ${_var_name//<search>/<replace>}
de Bash^
, nesse contexto, é o inverso ou not
para pesquisas do tipo regexEmbora eu consiga que isso
printf
seja melhor em quase todos os casos de uso, o código acima usaecho
para não confundir excessivamente o que está acontecendo.
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