如何将命令回显到其他文件

如何将命令回显到其他文件

我想从一个脚本回显到另一个脚本,但我不想获取命令的输出,因为我想在另一个脚本中使用此命令,我需要创建一个为我创建 adduser.local 脚本的脚本。

第一个脚本是:

#!/bin/bash
sudo echo "
#!/bin/bash
'lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"' " >>
/usr/local/sbin/adduser.local

我从 /usr/local/sbin/adduser.local 获得的是命令的输出,我想按原样复制命令,因为我不想在第一个脚本中获取输出,我想在第二个脚本中获取输出。所以我需要知道如何使用 echo 权限,使第一个脚本将命令按原样丢弃到 adduser.local。

首次运行后,adduser.local 脚本需要如下所示

#!/bin/bash
lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"
#and now i can use the $lastuser in this script
echo " '$lastuser' ALL = !/usr/bin/apt-get update " >> /etc/sudoers

答案1

你可能不应该这样做。你也许可以通过不编写一个脚本来生成另一个脚本(稍后修改并运行该脚本)的方式来实现你的目标;见下文。但如果你真的想这样做,并且想用与你所展示的代码非常相似的代码来做这件事,那么steeldriver 是对的,这里的文件是一个可行的办法。

steeldriver 使用此处文档的方式很好;这里还有另一个,其代码稍微简单一些。(我介绍它主要是为了有机会解释其语法的每个部分的含义,而不是因为相信这种方法更优越。)

#!/bin/bash
cat >/usr/local/sbin/adduser.local <<'EOF'
#!/bin/bash
lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"
EOF

/usr/local/sbin/adduser.local如果第二个脚本的名称不同,请将其替换为您想要的名称。然后只需以 root 身份运行脚本,例如使用sudo此脚本的全部目的是在只有 root 具有写访问权限的位置创建一个文件,因此它本身就是以 root 身份运行的那种命令sudo。当您有一个脚本,其中每个命令都以sudo(开头时尤其如果它是一个单命令脚本),这通常表明该脚本sudo根本不应该在其中使用,而应该只使用 来运行sudo

根据您运行生成的脚本的方式,您可能需要授予它执行权限,您可以使用chmod +x。(这适用于钢铁司机之路,也是如此。)如果该文件已经存在且具有执行权限,而您正在覆盖它,那么您不需要运行chmod

上面显示的命令的工作方式是:

  • 什么时候cat运行时没有文件名参数(就像这里的情况一样),它只是将其输入复制到其输出。
  • cat的输出被重定向到/usr/local/sbin/adduser.local文件输出重定向运算符>。我使用了>覆盖运算符,尽管您使用的是>>附加运算符。我这样做是因为我假设您想覆盖该文件,因为您放入其中的文本以哈希邦,这通常没有什么意义,除非在文件开头
  • cat的输入取自下一行出现的文本,直到但不包括以 开头的任何行EOF,由这里的文件表示法<<
  • 引用EOF之后<<——也就是说,写<<'EOF'而不是<<EOF——抑制扩展在此处文档的主体中,这样,运行第一个脚本的 shell 就不会对其中的 bash 代码中的任何字符进行特殊处理。

使用 here document 可以消除嵌套在其他引号中的引号所带来的困难。如果您需要 here document 的主体包含EOF,那没问题,因为虽然EOF是常用的单词之一,但它一点也不特别。您可以使用任何您喜欢的单词。只需在<<您希望作为输入提供的最后一行之后单独出现的行之后和行首使用它即可——就像EOF上面使用的一样。


有几个原因使得echo在您描述的情况下您可能不应该实际上这样做(也不应该使用任何基于的方法)。

首先,如果您的目标是允许非 root 用户安装更新,那么编辑sudoers可能不是实现该目标的最佳方式。还有其他方法;例如,您可以安排自动无人值守安装的更新,或让非 root 用户使用更新管理器你可能感兴趣这种技术或者它的一些变体。我不太清楚你的要求是什么,但你可能想问一下无论具体问题你正在尝试解决。

其次,如果你最终编辑/etc/sudoers,那么不采用自动检查语法错误并拒绝引入错误修改的方式通常是不好的。(在目录中创建或编辑 sudoers 文件通常/etc/sudoers.d比修改主 sudoers 文件更好/etc/sudoers,但需注意相同的事项和注意事项。)当您使用命令手动编辑 sudoers 文件时visudo,会执行此类检查;您正在编辑的文件不是真正的 sudoers 文件,而是一个临时文件,它会被检查并在通过语法检查后才复制到真正的 sudoers 文件中。

任何 sudoers 文件中最轻微的语法错误都会导致 sudo 拒绝允许任何人以 root 身份执行操作!这通常很容易修复,但如果您不使用基于 Polkit 的方法的原因是这是一个没有 Polkit 的服务器系统,那么就有点困难了。如果您必须编辑未通过 的 sudoers 文件visudo,则可以采取预防措施,打开 root shell,与您正在运行修改配置的命令的 shell 分开,例如通过运行sudo -i。一旦启动,只要它正在运行,它就会一直可用,即使它已sudo损坏。

实际上用来visudo检查对 sudoers 文件的自动脚本修改的语法正确性!这是可能的,因为它接受任何命令作为用于编辑文件的文本编辑器;这可以visudo使用SUDO_EDITOR环境变量进行一次自定义,您可以编写一个脚本,该脚本的行为与该编辑器相同,但自动化且不需要交互(除非它产生visudo阻塞的语法错误)。我认为细节超出了这个答案的范围;如果你想要帮助做这样的事情,你可以问另一个问题。

第三,你似乎计划为单个用户在 sudoers 文件中添加多个(可能很多)条目。如果是这样,你应该考虑为某个用户添加一个条目团体并将用户添加到组中。这种方法允许 Ubuntu 系统上的管理员使用 以 root 身份运行任意命令sudo;此类用户是sudo组的成员,该组有一个 条目。您可以创建其他组并授予他们其他权限,这些权限可能比该组运行任意命令/etc/sudoers的能力更严格。sudo

第四,即使您确实想遵循所采用的方法,也存在比让一个脚本嵌入用于播种您手动修改的其他脚本的片段更好的方法。我认为您可能会发现最有用的两种方法是:

  • 您可以放入lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"一个文件,需要不是不可执行,也不以 hashbang 行开头#!,然后来源该文件位于将要使用的任何脚本中lastuser,方法是让这些脚本包含命令. lastuser.sh(或source lastuser.sh,在 bash 中等效),其中lastuser.sh是包含命令的文件的名称。lastuser变量在命令运行时定义. lastuser.sh,因此它仍然始终取决于的当前状态/etc/passwd
  • 如果你确实希望一个脚本创建另一个脚本,那么你可以创建一个包含它的主文件,其中包含第一个脚本,而不是嵌入将被复制的代码到第一个脚本中复制该文件复制到所需位置。您可以使用cp或者install

答案2

用一个这里的文件,确保引用分隔符词,以便 shell 不会扩展正文中的任何内容:

#!/bin/bash    

cat << 'EOF' | sudo tee -a /usr/local/sbin/adduser.local
#!/bin/bash
lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"
EOF

因为使用teeis becausesudo echo "..." >> somefile并没有达到你想象的效果 - 参见在 Bash 中使用带重定向的 sudo 时如何解决“权限被拒绝”?

相关内容