sudo를 사용해도 SSH를 통해 파일에 데이터를 쓰면 권한 오류가 발생합니다.

sudo를 사용해도 SSH를 통해 파일에 데이터를 쓰면 권한 오류가 발생합니다.

자동화 스크립트를 작성 중입니다. 그 일환으로 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

리디렉션은 실행하기 전에 일반 사용자로 쉘에서 수행됩니다 sudo.

댓글에 대한 답변으로 편집:

쉘은 이를 다른 명령과 비교하여 특정 명령으로 보지 않으며 해당 명령이 상승된 권한으로 실행될 것이라는 sudo것을 알지 못합니다 .sudo

쉘의 동작은 다음과 유사합니다.

/bin/echo some text > file

쉘은 위의 명령줄 중 하나를 구문 분석할 때 리디렉션을 찾습니다. 따라서 먼저 파일을 연 다음 fork프로그램이 실행할 프로세스, dup파일 설명자 stdout및 프로그램을 엽니다 exec. 그런 다음 리디렉션이 이미 있는 상태에서 실행하거나 /bin/echo.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다른 가능한 문제가 아닌 리디렉션과 관련된 문제를 해결하는 데 중점을 둡니다. 사용자가 언급했듯이카스주석에서 변수는 개별적으로 또는 전체 문자열로 인용되어야 합니다.

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가 설명했듯이 문제는 ssh를 통해 문자열을 원격 호스트로 보내기 전에 로컬 쉘이 메타 문자 [>"를 해석한다는 것입니다.

"tee" 명령을 사용하는 또 다른 방법은 백슬래시 "\"[">" 또는 다른 메타 시퀀스(예: ">>", "$1", "*" 등의 메타 문자)를 사용하여 문제가 되는 명령을 간단히 이스케이프하는 것입니다. ..] 그래서 당신은 다음과 같은 것을 갖게 됩니다:

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

또한 echo 문의 "*" 문자가 문제를 일으키지 않는 이유는 로컬에서 발생할 수 있는 쉘 확장을 억제하기 위해 하드(작은따옴표) 쌍으로 묶여 있기 때문이라는 점을 지적하고 싶습니다.

또한 이 예에서는 $BACKUP_USER 및 $SCRIPT 환경이 원격 시스템이 아닌 로컬로 정의된다는 점에 유의하세요. 원격 시스템에 정의된 환경을 사용하려면 "$" 기호를 이스케이프해야 합니다.

간단한 경험 법칙: 문자열이 따옴표 없이 또는 부드러운(큰) 따옴표 안에 전송되면 메타 시퀀스를 이스케이프해야 할 수도 있습니다. 큰 따옴표로 묶인 경우 일반적으로 이스케이프할 필요가 없습니다.

이는 모두 대상 파일에 쓸 수 있는 권한이 있다고 가정합니다. 그렇지 않은 경우 대안은 @Bobo가 설명한 대로 "tee" 명령을 사용하거나 권한이 있는 위치에 파일을 만들고 해당 위치로 이동("mv")하는 것입니다.

관련 정보