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

Lor*_*eno 3 bash ssh sudo io-redirection shell-script

我正在创建一个自动化脚本。作为其中的一部分,我想添加一个 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"
Run Code Online (Sandbox Code Playgroud)

有问题的命令是:

sudo echo '*/1 * * * *' $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME > /etc/cron.d/discourse-backup
Run Code Online (Sandbox Code Playgroud)

我越来越:

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

在此之前,一切都按原样执行。我的最后一条命令有什么问题?我认为这是引号的一些问题 - 我尝试了单引号和双引号的多种组合,但最终得到了相同(或更糟)的结果。

Bod*_*odo 7

当你运行像这样的命令时

sudo echo some text > file
Run Code Online (Sandbox Code Playgroud)

在运行之前,重定向是由您的 shell 作为普通用户完成的sudo

编辑,回答评论:

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

外壳的行为将与

/bin/echo some text > file
Run Code Online (Sandbox Code Playgroud)

当 shell 解析上述命令行之一时,它会找到重定向。所以它将首先打开文件,然后fork是程序执行的进程,dup文件描述符stdoutexec程序。然后,要么/bin/echosudo与运行stdout已经重定向。

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

尝试类似的东西

echo '*/1 * * * *' $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME | sudo tee /etc/cron.d/discourse-backup >/dev/null
Run Code Online (Sandbox Code Playgroud)

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

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

echo "*/1 * * * * $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME"  | sudo ...
Run Code Online (Sandbox Code Playgroud)

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

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

ssh -i ./ssh-key user@server "
    ...
    echo \"*/1 * * * * $BACKUP_USER /home/$BACKUP_USER/bin/$SCRIPT_NAME\" | sudo ... "
Run Code Online (Sandbox Code Playgroud)