将source与包含sudo命令的脚本一起使用

时间:2016-12-20 21:04:15

标签: linux bash shell sudo

我有一个在服务器之间复制文件的脚本。我正在使用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}")`.

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

1 个答案:

答案 0 :(得分:1)

你真正想要的更像是:

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

让我们回顾一下为什么其他方法不能一次一个地工作:

  • source

    下运行sudo su -c
    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. 即使您的/bin/sh由bash提供,仍然无法使用source:启动/bin/sh的新副本并将您的脚本导入其中,您在新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"

...显示有问题的代码确实按照描述工作。