![sudo를 사용해도 SSH를 통해 파일에 데이터를 쓰면 권한 오류가 발생합니다.](https://linux55.com/image/14667/sudo%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%B4%EB%8F%84%20SSH%EB%A5%BC%20%ED%86%B5%ED%95%B4%20%ED%8C%8C%EC%9D%BC%EC%97%90%20%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC%20%EC%93%B0%EB%A9%B4%20%EA%B6%8C%ED%95%9C%20%EC%98%A4%EB%A5%98%EA%B0%80%20%EB%B0%9C%EC%83%9D%ED%95%A9%EB%8B%88%EB%8B%A4..png)
자동화 스크립트를 작성 중입니다. 그 일환으로 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
.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
다른 가능한 문제가 아닌 리디렉션과 관련된 문제를 해결하는 데 중점을 둡니다. 사용자가 언급했듯이카스주석에서 변수는 개별적으로 또는 전체 문자열로 인용되어야 합니다.
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")하는 것입니다.