我正在创建一个自动化脚本。作为其中的一部分,我想添加一个 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
文件描述符stdout
和exec
程序。然后要么在已经重定向的情况下运行/bin/echo
or 。sudo
stdout
在您的用例中,以普通用户身份打开文件进行重定向将会失败。
尝试类似的东西
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”)到位。