通过 SSH 将数据写入文件存在权限错误,即使使用 sudo

通过 SSH 将数据写入文件存在权限错误,即使使用 sudo

我正在创建一个自动化脚本。作为其中的一部分,我想添加一个 cron 作业。这是失败的脚本的一部分:

BACKUP_USER=backupbot
SCRIPT_NAME=backup-script.sh

scp -i ./ssh-key ./$SCRIPT_NAME user@server:/tmp
ssh -i ./ssh-key user@server "
    sudo mv /tmp/$SCRIPT_NAME /home/$BACKUP_USER/bin/ &&
    sudo chown $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME &&
    sudo chmod 100 /home/$BACKUP_USER/bin/$SCRIPT_NAME &&
    sudo sed -i 's/THE_URL/'${1}'/' /home/$BACKUP_USER/bin/$SCRIPT_NAME &&
    sudo echo '*/1 * * * *' $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME > /etc/cron.d/discourse-backup"

有问题的命令是:

sudo echo '*/1 * * * *' $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME > /etc/cron.d/discourse-backup

我越来越:

bash:第 5 行:/etc/cron.d/discourse-backup:权限被拒绝

直到这一刻,一切都按其应有的方式执行。我的最后一个命令有什么问题?我认为这是引号的问题 - 我尝试了单引号和双引号的多种组合,但最终得到了相同(或更差)的结果。

答案1

当您运行类似命令时

sudo echo some text > file

重定向是由您的 shell 在运行之前以普通用户身份完成的sudo

编辑,回复评论:

与其他命令相比,shell 不会将其sudo视为任何特定命令,并且它不知道该命令sudo将以提升的权限运行。

shell 的行为与

/bin/echo some text > file

当 shell 解析上面的命令行之一时,它会找到重定向。因此,它将首先打开文件,然后打开fork一个供程序执行的进程、dup文件描述符stdoutexec程序。然后要么在已经重定向的情况下运行/bin/echoor 。sudostdout

在您的用例中,以普通用户身份打开文件进行重定向将会失败。

尝试类似的东西

echo '*/1 * * * *' $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME | sudo tee /etc/cron.d/discourse-backup >/dev/null

在这种情况下,该文件是一个命令行参数,sudo它将运行,root然后将文件名参数传递给tee该参数,然后将以提升的权限执行该参数。这将允许tee打开文件进行写入。

第二次编辑:这个答案的重点是解决sudo与重定向相关的问题,而不是其他可能的问题。正如用户提到的CAS在注释中,变量应该单独或作为整个字符串引用,例如

echo "*/1 * * * * $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME"  | sudo ...

在问题的用例中,由于两个原因,引用可能不太重要。参数仅用于echo,并且输出必须是有效crontab行。无论如何,这会禁止变量中存在多个“有问题”的字符。但一般来说,始终建议正确引用。

由于此命令将是较长带引号的字符串的一部分,因此可以转义引号,例如

ssh -i ./ssh-key user@server "
    ...
    echo \"*/1 * * * * $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME\" | sudo ... "

答案2

正如 @Bodo 所解释的,问题是本地 shell 在通过 ssh 将字符串发送到远程主机之前解释元字符 [在本例中为“>”]。

使用“tee”命令的另一种方法是简单地使用反斜杠“\”[“>”或任何其他元序列(例如“>>”、“$1”、“*”等)转义有问题的元字符...] 这样你就有了类似的东西:

sudo echo '*/1 * * * *' $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME \> /etc/cron.d/discourse-backup

我还想指出,echo 语句中的“*”字符没有产生问题的原因是它们被括在硬(单)引号对中,以抑制本来会在本地发生的 shell 扩展。

另外,在此示例中,请注意环境 $BACKUP_USER 和 $SCRIPT 是本地定义的,而不是在远程系统上定义的。如果您想使用远程系统上定义的任何环境,则需要转义“$”符号。

一个简短的经验法则:如果传输的字符串未加引号或在软(双)引号内,则可能需要转义元序列。如果它在硬(单)引号中,通常不需要转义

这一切都假设您有权写入目标文件。如果不这样做,替代方法是使用 @Bobo 所解释的“tee”命令,或者在您有权限的位置创建一个文件,然后将其移动(“mv”)到位。

相关内容