【问题标题】:Use source with script that contains sudo command将源代码与包含 sudo 命令的脚本一起使用
【发布时间】:2016-12-20 21:04:15
【问题描述】:

我有一个在服务器之间复制文件的脚本。我正在使用 lsof 命令来确保文件在移动之前没有被写入。运行脚本的用户和写入文件的用户不同,所以我需要对文件所有者进行 sudo。这是 sudoers 文件中的相关行:

userA ALL=(userB:userB) NOPASSWD: ALL

在主脚本(以 userA 身份运行)中,我尝试调用 sudo,然后调用包含 lsof 命令的下标:

sudo su - userB -c 'source ./getOpenFiles.sh'

getOpenFiles.sh 有这一行:

#!/bin/bash 
lsofResult=$(/usr/sbin/lsof "${sourcePath}")

我也试过调用下标:

source ./getOpenFiles.sh

那么下标的第一行就是sudo:

#!/bin/bash
sudo su - banjobs
lsofResult=$(/usr/sbin/lsof "${sourcePath}")`.

这两种解决方案都不起作用。

【问题讨论】:

  • 当你运行sudo su - banjobs 时,下一个命令直到你的sudo su 完成并退出后才会运行,并且没有任何东西以banjobs 运行。
  • 也就是说它不会将lsofResult 评估为banjobs
  • ...如果你使用su -c 'source somescript',那么somescriptsh 运行,而不是bash,不管它的shebang 说什么。如果您的sh 不支持source,那么它根本不会运行。 (编写source 的POSIX 兼容方式是. somescript,而不是source somescript)。
  • ...也就是说:这里有很多错误,并不是所有的都与source有关。 (尽管如果您希望 source 导致在父 shell 中设置变量 - 即运行您的 sudo 命令的 shell,那将永远无法工作,因为 sudo 本身就是一个子进程 - - source 的重点是直接在您当前的 shell 进程中做某事;如果您在子进程中做任何事情,那完全违背了这一点)。
  • 顺便说一句,打算引入 bash 的代码应该以 .bash 扩展名命名,而不是 .sh 扩展名——这样对读者来说代码更明显不打算与 POSIX sh 兼容,但特别是只有在带有 bash 扩展的解释器中才能安全。 (这对于您在此处提供的特定代码并不重要,除了 source is POSIX-sh-compatible,但认为它是最佳实践说明)。相比之下,对于旨在执行而非来源的命令,根本不具有任何文件扩展名更为合适。

标签: linux bash shell sudo


【解决方案1】:

你真正想要的更像是:

lsofResult=$(sudo -u banjobs lsof "${sourcePath}")

让我们来看看为什么其他方法一次都行不通:

  • sudo su -c下运行source

    sudo su - userB -c 'source ./getOpenFiles.sh'
    

    ...使用sudo 运行su,后者运行sh -c 'source ./getOpenFiles.sh'。由于几个独立的原因,这不起作用:

    1. sh -c 'source ./getOpenFiles.sh' 依赖于 source 关键字在 /bin/sh 中可用,但这是一个 bash 扩展。

    2. 1234563在新的 shell 中,而不是在 启动 sudo su 的原始 shell 中。
  • 运行sudo su - banjobs,然后运行lsofResult=$(/usr/sbin/lsof "${sourcePath}")

    ...表示lsofResult=$(...) 直到sudo su - banjobs 退出后才会运行。如果sudo su - banjobs 已退出,则当前用户不再是banjobs,因此sudo 命令对lsof 没有任何影响。


详细演示如何对此进行测试(针对系统上没有banoffuserB 帐户的人):

# place relevant contents in sourceme.bash
# switching from lsof to fuser for this test since OS X lsof does not accept a directory
# as an argument.
cat >sourceme.bash <<'EOF'
lsofResult=$(sudo -u root fuser "${sourcePath}" 2>&1)
EOF

# set sourcePath in the outer shell
sourcePath=$PWD
source sourceme.bash
declare -p lsofResult

...在我的系统上,输出类似于以下内容:

declare -- lsofResult="/Users/chaduffy/tmp: 17165c 17686c 17687c 17688c 17689c 17690c"

...表明有问题的代码确实按照描述的那样工作。

【讨论】:

  • 感谢您的回答查尔斯。不幸的是,您的解决方案仍然无效。我在下标和主脚本中都试过了。
  • @Stu,我需要查看一个完整的复制器,确切地显示您如何使用它(调用和收集值的评估)。如果正确使用,这肯定会“起作用”——我很高兴在问题中编辑一个例子来说明这一点。
  • @Stu, ...添加了这样的例子。
  • 谢谢你的建议,查尔斯。我们已决定允许脚本在文件所有者下运行,因此现在不需要全部使用 sudo。再次感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-13
  • 1970-01-01
  • 2011-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多