/etc/profile
我正在创建一个命令,该命令将通过脚本更改文件中的某一行,但是在某些版本的 Linux 中,该sudo
命令可能不会被激活,因此有必要su
在执行时在脚本中使用该命令:
文件内/etc/profile
有以下行:
if [ "`id -u`" = "0" ]; then
echo $PATH | grep /usr/local/sbin 1> /dev/null 2> /dev/null
if [ ! $? = 0 ]; then
PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH
fi
fi
所以我这样做了:
$ PROFILE="/etc/profile"
$ sed '/\"`id -u`\"/ s/^if/# if/g;/\"`id -u`\"/ s/$/\nif [[ \"\$(id -u)\" == \"0\" || \"\$(id -un)\" == \"\${HOME##*\/}\" ]]; then/g;' ${PROFILE}
# if [ "`id -u`" = "0" ]; then
if [[ "$(id -u)" == "0" || "$(id -un)" == "${HOME##*/}" ]]; then
echo $PATH | grep /usr/local/sbin 1> /dev/null 2> /dev/null
if [ ! $? = 0 ]; then
PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH
fi
fi
该命令似乎可以正确执行以更改文件,但是使用以下su -c
命令执行此操作时:
$ PROFILE="/etc/profile"
$ su -c "sed '/\"`id -u`\"/ s/^if/# if/g;/\"`id -u`\"/ s/$/\nif [[ \"\$(id -u)\" == \"0\" || \"\$(id -un)\" == \"\${HOME##*\/}\" ]]; then/g;' ${PROFILE}"
if [ "`id -u`" = "0" ]; then
echo $PATH | grep /usr/local/sbin 1> /dev/null 2> /dev/null
if [ ! $? = 0 ]; then
PATH=/usr/local/sbin:/usr/sbin:/sbin:$PATH
fi
fi
它要求输入密码并读取变量中的文件$PROFILE
,但不修改该行。命令有什么问题su -c
?
答案1
注意:所有代码都是经测试在 Slackware64 15.0 虚拟机中。
字面答案
正如 @ilkkachu 指出的,在命令的第二种形式中(使用苏(1)) 您在双引号内使用单引号。单引号和双引号遵循不同的规则;另请参阅[1]和[2]。此外,只需要一个正则表达式。
正如 @waltinator 提醒的那样,您应该保留所有重要修改文件的备份,这/etc/配置文件是。 GNUsed可以-i
选择创建备份,遗憾的是不可移植,因此替代方法是首先创建修改文件的备份副本,然后对该备份副本进行操作并将标准输出重定向到新文件。
所以,你的命令应该是:
su -c 'cp /etc/profile /etc/profile.bak; sed "s,^\\(if \\[ \"\`id -u\`\".*\\)\$,\\#\\1\\
if [[ \"\$(id -u)\" == \"0\" || \"\$(id -un)\" == \"\${HOME##*/}\" ]];\
then," /etc/profile.bak > /etc/profile'
然而,为了保持合规POSIX嘘(1p)(另:[3]),您应该避免非 POSIX 构造,例如
if [[ ... == ... || ... == ... ]]; then ...
相反,您可以使用
if [ ... = ... ] || [ ... = ... ]; then ...
像这样:
su -c 'cp /etc/profile /etc/profile.bak; sed "s,^\\(if \\[ \"\`id -u\`\".*\\)\$,\\#\\1\\
if [ \"\$(id -u)\" = \"0\" ] || [ \"\$(id -un)\" = \"\${HOME##*/}\" ];\
then," /etc/profile.bak > /etc/profile'
您还可以避免执行苏彻底改变/etc/配置文件,如果文件/etc/profile.bak已经存在:
if [ ! -f /etc/profile.bak ]; then
su -c 'cp /etc/profile /etc/profile.bak; sed "s,^\\(if \\[ \"\`id -u\`\".*\\)\$,\\#\\1\\
if [ \"\$(id -u)\" = \"0\" ] || [ \"\$(id -un)\" = \"\${HOME##*/}\" ];\
then," /etc/profile.bak > /etc/profile'
fi
替代(正确)方法
从评论来看,您实际上想做的是自动创建能够使用的用户帐户须藤(8)并且也已经/usr/local/sbin:/usr/sbin:/sbin
添加到他们的PATH
.这可以轻松实现,而无需更改重要的系统文件,例如/etc/配置文件。
为此,您应该:
- 以 root 身份登录。如果您创建一个脚本(例如:
createuser
,它接受用户名作为第一个参数,我们称之为newuser
)来自动创建用户,则可以通过将其传递给须藤或者苏,例如。su -c 'createuser newuser'
。 - (从这里到结束,可能在脚本内部)使用以下命令创建新用户帐户:
useradd -m newuser
- 添加
newuser
/etc/sudoers,所以可以执行须藤获取root权限:
printf "newuser ALL=(ALL:ALL) ALL\n" >> /etc/sudoers
在脚本中,这会有些不同。如果您已将用户名保存在变量中user
:
printf "%s ALL=(ALL:ALL) ALL\n" "$user" >> /etc/sudoers
- 前置
/usr/local/sbin:/usr/sbin:/sbin
到PATH
in/home/newuser/.profile定制他的环境:
printf "%s\n" 'export PATH=/usr/local/sbin:/usr/sbin:/sbin${PATH+:}"$PATH"' \
>>/home/newuser/.profile
- 更改所有权和权限/home/newuser/.profile:
chown newuser:newuser /home/newuser/.profile
chmod 644 /home/newuser/.profile
- 设置密码
newuser
(需要 tty 更改密码):
passwd newuser
或将其设置为“已到期”,这将强制用户在下次登录时设置它,并且不需要 tty:
passwd -e newuser
附录
如果您打算结合这两个要求,并设置或保留PATH
在通过执行 sudo 创建的环境内部, 看如何保留sudo
$PATH?。请注意,在 Slackware64 15.0 中,除了上述“替代方法”中的步骤之外,默认情况下不需要其他步骤:
newuser@darkstar:~$ sudo sh -c 'printf "%s\n" "$PATH"'
/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/lib64/qt5/bin
参考
- POSIX Shell 命令语言,(2.2 引号、2.2.2 单引号、2.2.3 双引号),
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - Bash 手册,3.1.2 引用,
https://www.gnu.org/software/bash/manual/html_node/Quoting.html - POSIX Shell 命令语言,
https://pubs.opengroup.org/onlinepubs/9699919799/idx/shell.html