回答:
他の回答では、最初から一定量の文字がマスクされ、プレーンテキストのサフィックスの長さが異なります。別の方法は、プレーンテキストに一定量の文字を残し、マスクされた部分の長さを変えることです。どちらがより有用かはわかりませんが、他の選択肢は次のとおりです。
#!/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
、短い文字列を変更して、文字列の大部分がマスクされるようにすることもできます。たとえば、これにより、短い文字列でも少なくとも3文字がマスクされます。(つまり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"
}
1つのオプションはecho
、次のような関数を使用するように強制することです。
obfuprint() {
if [ "${#1}" -ge 8 ]
then
printf '%s\n' "${1/????????/********}"
else
printf '%s\n' "${1//?/*}"
fi
}
次にobfuprint 'secretvalue'
、********lue
(末尾の改行を使用して)呼び出して受信できます。この関数は、パラメーター展開を使用して、渡された値の最初の8文字を検索し、それらを8つのアスタリスクに置き換えます。入力値が8文字より短い場合、それらはすべてアスタリスクに置き換えられます。8つ以上の文字入力の最初の仮定を指摘してくれた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/^......../*********/'; }
sed 's/^......../********/' <<< 'secretvalue'
bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo
。
zsh
テキストの4分の3をマスクするバリアント:
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のもう1つのオプションは、単純なものeval
を気にしない場合は、次の2つの方法で実行できます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]
Bashの<search>
内部として完全に有効で便利です${_var_name//<search>/<replace>}
^
このコンテキスト内では、逆または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