![将密码 (cat) 传递给 sed 以替换配置值](https://linux22.com/image/189736/%E5%B0%86%E5%AF%86%E7%A0%81%20(cat)%20%E4%BC%A0%E9%80%92%E7%BB%99%20sed%20%E4%BB%A5%E6%9B%BF%E6%8D%A2%E9%85%8D%E7%BD%AE%E5%80%BC.png)
我有一个名为的配置文件,.env
其中包含:
DB_PASSWORD={password}
其中/root/.mysql/db00.yml.db
我们有 MySQL root 帐户的密码。我正在尝试将其sed
通过以下方式传递:
cat /root/.mysql/db00.yml.db | sed -i -e "s/DB_PASSWORD=/DB_PASSWORD=(.*)/g" .env
没有任何运气,尝试了一些变化,例如:
sed -i "s/DB_PASSWORD=/DB_PASSWORD=$(cat /root/.mysql/db00.yml.db)" .env
mysqlpwd=$(cat /root/.mysql/db00.yml.db)
# Use the variable in sed -i
sed -i "s/DB_PASSWORD=/DB_PASSWORD=$mysqlpwd/g" .env
这会产生错误:
root@linuxbox:/var/www/www.example.com# mysqlpwd=$(cat /root/.mysql/db00.yml.db)
root@linuxbox:/var/www/www.example.com# sed -i "s/DB_PASSWORD=/DB_PASSWORD=$mysqlpwd/g" .env
sed: -e expression #1, char 33: unknown option to `s'
更新:
不运行它/g
也会失败:
root@linuxbox:/var/www/www.example.com# echo $mysqlpwd
Rjcr/Sn+s/a2QbGx
root@linuxbox:/var/www/www.example.com# cat .env | grep DB_PASSWORD
DB_PASSWORD=(.*)()
root@linuxbox:/var/www/www.example.com# sed -i "s/DB_PASSWORD=/DB_PASSWORD=$mysqlpwd/" .env
sed: -e expression #1, char 33: unknown option to `s'
这些方法似乎都不起作用。
我正在跑步sed 4.7
,即:
root@linuxbox:/var/www/www.example.com# sed --version
sed (GNU sed) 4.7
答案1
就其本质而言,密码必须允许包含键盘可以可靠地产生的任何字符。这意味着密码可以轻松包含有效sed
代码或字符串,当它们注入sed
编辑脚本时,会破坏该脚本,写入系统上的任意文件,或者使用 GNUsed
执行任意命令(当您运行为root,你看起来就是)。
当您需要使用用户提供的数据时,请勿使用sed
,除非您确切知道如何清理它。我个人会避免sed
任何需要我双引号表达式sed
(而不是单引号)的事情,以允许 shell 扩展我几乎无法控制的变量。
相反,使用awk
:
awk -F '=' '
BEGIN { OFS = FS }
NR == FNR { password = $0; next }
$1 == "DB_PASSWORD" { sub("=.*",""); $2 = password }; 1' /root/.mysql/db00.yml.db .env >.env.new &&
mv .env.new .env
首先从第一个文件的第一行读取密码(假设该文件仅包含一行包含逐字密码)。
然后,它将您的文件视为由- 分隔字段.env
组成的文件。=
当一行中的第一个字段为 时DB_PASSWORD
,它会清除该行第一个=
字段之后的所有内容(以防万一旧密码包含=
),并将密码插入作为第二个字段。
所有行,无论是否修改,都会输出到.env.new
,然后该文件将旧的替换.env
为mv
。
至关重要的是,我从不将从两个文件中读取的数据用作代码在我的awk
程序中,我从来不允许awk
将密码的任何部分视为特殊的。请注意,在调用中使用密码作为替换字符串sub()
会出现问题,因为这会将&
字符串中的任何内容视为特殊字符串。
答案2
尝试为 sed 使用不同的分隔符...仍然存在失败的风险,具体取决于您的实际密码(例如,如果包含|或者&或者\1)。
sed -i "s|DB_PASSWORD=|DB_PASSWORD=$mysqlpwd|" .env
答案3
您不应该将密码放在命令行参数中;系统上的任何用户都可以通过ps
或top
或多种其他方式读取它们。我知道在某些自动化场景中这可能不太可能(因为没有人可能会登录到盒子中)但这仍然是一个坏主意,并且总是有可能某些监视工具或其他人的某些脚本会碰巧记录在某个时间点在系统上运行的进程,从而将您的密码记录到谁知道在哪里。
使用 已经给出了一个很好的答案awk
;我还编写了一个简单的解决方案,ex
我将使用它来分享。这适用于任何带有任何特殊字符的密码,唯一的例外是它不能结尾在反斜杠中。
如果文件.env
包含:
somevar1=someval
somevar2=some other val
DB_PASSWORD=
somevar3=another val
somevar4=val
并myscript
包含:
/^DB_PASSWORD=$/a
!@#$#% some complicated password "^$%^&@#,.,cmxz\k'dvok][
.
0//j!
x
只需运行ex .env < myscript
即可得到如图所示的结果:
$ ex .env < myscript
$ cat .env
somevar1=someval
somevar2=some other val
DB_PASSWORD=!@#$#% some complicated password "^$%^&@#,.,cmxz\k'dvok][
somevar3=another val
somevar4=val
$
答案4
sed -i -e "
/^DB_PASSWORD=/c\\
DB_PASSWORD=$(sed -e 's:[\\]:&&:g' /root/.mysql/db00.yml.db)
" ./.env
- 我们在 sed 代码本身中集成了密码清理功能,以确保更改命令中的插入价值
c\