【问题标题】:Substituting password parameter value in bash在bash中替换密码参数值
【发布时间】:2015-10-22 00:59:46
【问题描述】:

我有一个在 Linux 机器上运行的脚本,它读取命令并在某些事件上调用程序。

我们需要记录这些命令,但是在使用密码参数时过滤/替换密码参数,方法是连续输入五个 X (XXXXX)。

输入示例

bash 脚本接收的输入有一个命令类型,后跟各种参数,如下所示:

  • adduser --username="foo" --password="bar"
  • remove --username="foo"
  • listusers
  • changepass --username="foo" --password="bar"

基本格式为command parameter="" parameter=""...

记录值示例

上面的值在日志中看起来像这样:

  • adduser --username="foo" --password="XXXXX"
  • remove --username="foo"
  • listusers
  • changepass --username="foo" --password="XXXXX"

我的尝试

我尝试使用 bash 替换,但在第一种情况下,我们没有引用密码(我们后来发现这将通过引号传递)。它会切断密码后的一切。第二个选项根本不进行替换。

  • echo "${value%password=*}password=XXXXXX" >> somelog.log
  • echo "${value/password=\"(.*?)\"/password=xxxxx }" >> somelog.log

我觉得第二个选项很接近,但我错过了一些东西。如果有人可以指导我,将不胜感激。

【问题讨论】:

  • 你的问题意味着另一个问题;您是否将$value 传递给eval?我建议修改脚本,使value 实际上是一个数组,例如cmd=(adduser --username="foo" --password="bar")。然后您将使用"${cmd[0]}" "${cmd[@]1:}" 执行,并使用${cmd[@]/password=*/password="XXX"} 登录;替换分别应用于每个数组元素,而不是整个命令行。

标签: regex linux bash passwords


【解决方案1】:

我不喜欢 bash 替换,而是更喜欢使用 sed 来完成这样的任务。怎么样:

echo "$value"|sed 's/password="[^"]*"/password="XXXXX"/' >> somelog.log

?

【讨论】:

  • 不引用 "$value" 会丢失空白信息并扩展 glob/等。并且 sed 模式对于密码字符串中的转义双引号失败。
  • 这根本不像 RSchulze 的答案那么健壮,而且成本更高(因为它需要一个子外壳和一个外部进程)。例如,--password="foo\"bar" 的密码值失败。
  • 你说得对,@EtanReisner,RSchulze's 更加健壮和高效。
【解决方案2】:

是否需要在 bash 中本地执行此操作?

通过 sed 管道可能会更容易。但是,如果您想使用 bash,我建议您执行以下操作来更改以 --password= 为前缀的任何内容,后跟任何非空格(因此它会捕获带引号和不带引号的密码)。我使用了 // 以防需要在一行上有多个 --password 实例。需要在脚本中打开 extglob(扩展模式匹配)才能使其工作。

shopt -s extglob
"${value//--password=+([! ])/--password=XXXXX }"

参考:
http://wiki.bash-hackers.org/syntax/pattern
http://wiki.bash-hackers.org/syntax/pe#search_and_replace

测试数据:

adduser --username="foo" --password="bar"
adduser --username="foo" --password=bar
remove --username="foo"
listusers
changepass --username="foo" --password="bar" --something="else"
changepass --username="foo" --password="bar" --something="else" --password="again"

变成:

adduser --username="foo" --password=XXXXX
adduser --username="foo" --password=XXXXX
remove --username="foo"
listusers
changepass --username="foo" --password=XXXXX  --something="else"
changepass --username="foo" --password=XXXXX  --something="else" --password=XXXXX 

编辑:我忘了提到需要为此激活 extglob。

【讨论】:

  • 我的错,我想忘记了。感谢您指出这一点,我会重新添加它。
  • 这比我的回答要好得多(以及我试图让后向工作的尝试)。
  • 当我刚刚尝试您的示例时,我的输出将密码保存为纯文本。所以基本上,您正在寻找一个或多个不是空格的字符?抱歉,我的正则表达式阅读没有达到应有的水平,所以如果我对解释有误,请随时纠正我。我认为我们遇到了一个问题,因为密码值后面并不总是有空格。
  • 字符串替换中使用的 Bash 模式匹配不是“真正的”正则表达式,所以如果它看起来难以阅读也不要难过(普通的正则表达式有时可能已经够难了)。您的数据与我使用的测试数据不同吗?我忘了提到 extglob 需要处于活动状态,并稍后将其添加到我的答案中,因此您在测试时也可能丢失了。
  • shopt -s extglob 解决了这个问题。你是对的。我接受 sed 答案,因为它很简单。但我会赞成你的回答。你提供了一个很棒的解释,我验证它有效。谢谢!
【解决方案3】:

Shell 替换扩展是模式而不是正则表达式。

使用"${value/password=\"*\"/password=XXXXX}",但请注意,虽然它似乎可以处理密码字符串中的转义引号

如果您需要担心后面的参数,那么您需要使用其他东西(可以执行正则表达式)。

类似:

[[ "$f" =~ (.*password=)\"[^\"]*\"(.*) ]]; echo "${BASH_REMATCH[1]}XXXXX${BASH_REMATCH[2]}"

但这对转义引号有问题(它会提前结束匹配)。

但 RSchulze 的答案更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    相关资源
    最近更新 更多