su 命令错误

su 命令错误

/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/配置文件

为此,您应该:

  1. 以 root 身份登录。如果您创建一个脚本(例如:createuser,它接受用户名作为第一个参数,我们称之为newuser)来自动创建用户,则可以通过将其传递给须藤或者,例如。su -c 'createuser newuser'
  2. (从这里到结束,可能在脚本内部)使用以下命令创建新用户帐户:
useradd -m newuser
  1. 添加newuser/etc/sudoers,所以可以执行须藤获取root权限:
printf "newuser  ALL=(ALL:ALL) ALL\n" >> /etc/sudoers

在脚本中,这会有些不同。如果您已将用户名保存在变量中user

printf "%s  ALL=(ALL:ALL) ALL\n" "$user" >> /etc/sudoers
  1. 前置/usr/local/sbin:/usr/sbin:/sbinPATHin/home/newuser/.profile定制他的环境:
printf "%s\n" 'export PATH=/usr/local/sbin:/usr/sbin:/sbin${PATH+:}"$PATH"' \
      >>/home/newuser/.profile
  1. 更改所有权和权限/home/newuser/.profile:
chown newuser:newuser /home/newuser/.profile
chmod 644 /home/newuser/.profile
  1. 设置密码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

参考

  1. POSIX Shell 命令语言,(2.2 引号、2.2.2 单引号、2.2.3 双引号),
    https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02
  2. Bash 手册,3.1.2 引用,
    https://www.gnu.org/software/bash/manual/html_node/Quoting.html
  3. POSIX Shell 命令语言,
    https://pubs.opengroup.org/onlinepubs/9699919799/idx/shell.html

相关内容