Echo with obfuscation
One option would be to force yourself to use a function instead of echo
, such as:
obfuprint() {
if [ "${#1}" -ge 8 ]
then
printf '%s\n' "${1/????????/********}"
else
printf '%s\n' "${1//?/*}"
fi
}
Then you could call obfuprint 'secretvalue'
and receive ********lue
(with a trailing newline). The function uses parameter expansion to search for the first eight characters of the passed-in value and replaces them with eight asterisks. If the incoming value is shorter than eight characters, they are all replaced with asterisks. Thanks to ilkkachu for pointing out my initial assumption of eight-or-more character inputs!
Inspired by ilkkachu's flexible masking answer, I thought it'd be interesting to add a variation that randomly masks some percentage of the 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
}
This relies on bash's $RANDOM
special variable; it simply loops through each character of the input and decides whether to mask that character or print it. Sample output:
$ obfuprintperc 0123456789
0*****6*8*
$ obfuprintperc 0123456789
012***678*
$ obfuprintperc 0123456789
**********
$ obfuprintperc 0123456789
*****56***
$ obfuprintperc 0123456789
0*******8*
The other answers mask a fixed amount of characters from the start, with the plaintext suffix varying in length. An alternative would be to leave a fixed amount of characters in plaintext, and to vary the length of the masked part. I don't know which one is more useful, but here's the other choice:
#!/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
This prints **cde
and *********jkl
.
If you like, you could also modify n
for short strings to make sure a majority of the string gets masked. E.g. this would make sure at least three characters are masked even for short strings. (so abcde
-> ***de
, and 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"
}
You could try piping to sed
. For example, to replace the first 8 characters of a string with asterisks, you could pipe to the sed 's/^......../********/'
command, e.g.:
$ echo 'secretvalue' | sed 's/^......../********/'
********lue
You can also define a function that does this:
obsecho () { echo "$1" | sed 's/^......../*********/'; }