로컬 서버(위치 1)에서 원격 서버(위치 2)로 변수를 전달하려고 합니다. 이 코드의 목적은 원격 서버의 미리 정의된 위치에서 파일을 복사하는 것입니다. 간단히 말해서, 미리 정의된 경로를 사용하여 location2에서 location1로 파일을 복사하고 싶습니다. 여기서 location1은 로컬 서버에 있고 location2는 원격 서버입니다. 코드 조각을 살펴보세요.
$location1=somewhere/on/local_server
$location2=somewhere/on/remote_server
sshpass -p "password" \
ssh [email protected] 'su -lc "cp -r $location2 $location1";'
내가 얻는 오류는 $location1과 $location2가 모두 정의되지 않았다는 것입니다. 또한 위치 경로는 언제든지 변경될 수 있고 코드에서 변경하는 것이 수동으로 수행되면 고통스러울 수 있기 때문에 수동으로 입력하고 싶지 않습니다.
답변1
쉘 변수는 바로 쉘 변수입니다. 클라이언트 쉘의 이 변수는 이 ssh
명령이나 원격 호스트에서 시작된 쉘로 액세스할 수 없습니다.sshd
출구쉘 변수는 실행된 명령에 환경 변수로 전달됩니다. 따라서 내보내면 location1
환경 변수로 에 전달됩니다 . 구성 지시문( 또는 또는 ...을 통해) 을 ssh
사용하면 원격 호스트 로 전송을 시도합니다 .SendEnv
ssh
-o
~/.ssh/config
/etc/ssh/ssh_config
ssh
sshd
그러나 이것이 작동하려면 이 변수를 수신할 수 있는 구성 지시문 sshd
이 필요합니다 AcceptEnv
. 그러나 보안상의 이유로 일반적으로 그렇지 않습니다.
그러나 많은 기본 ssh/sshd 배포에서는 LC_
이름이 (현지화를 위해)로 시작하는 변수 전달을 허용합니다. 따라서 다음과 같은 이점을 누릴 수 있습니다.
LC_location1=$location1 LC_location2=$location2 ssh host
'su -lc '\''cp -r -- "$LC_location2" "$LC_location1"'\''
또는 로컬 셸 확장 변수를 원격 셸의 명령줄에 전달하도록 할 수 있습니다.
ssh host "su -lc 'cp -r -- $location2 $location1'"
그러나 이는 다음을 실행하는 것과 동일합니다.
eval eval "cp -r -- $location2 $location1"
즉, 이러한 변수는 인수로 전달되지 않고 쉘(원격 사용자의 로그인 쉘이며 에 의해 시작됨 ) 코드 cp
로 해석됩니다(두 번). 따라서 변수가 인 경우 극적인 결과가 발생합니다 .sh
su
$location1
/somewhere;rm -rf /
올바른 방법은 원격 셸을 올바르게 탈출하는 것입니다. 셸에는 두 가지 수준이 있으므로 작은따옴표를 두 번 이스케이프해야 합니다( ksh93
여기서는 // 구문이 사용됨).bash
zsh
escaped_location1=\'${location1//\'/\'\\\'\'}\'
escaped_location1=${escaped_location1//\'/\'\\\'\'}
escaped_location2=\'${location2//\'/\'\\\'\'}\'
escaped_location2=${escaped_location2//\'/\'\\\'\'}
ssh host "su -lc 'cp -r -- $escaped_location2 $escaped_location1'"
원격 사용자의 로그인 쉘은 Bourne과 유사하다고 가정합니다.
답변2
변수는 작은따옴표 사이에서 확장되지 않습니다.
큰따옴표를 사용하고 내부 큰따옴표를 이스케이프 처리합니다.
sshpass -p "password" \
ssh [email protected] "su -lc \"cp -r $location2 $location1\";"
또는 작은따옴표를 닫고 다시 엽니다.
sshpass -p "password" \
ssh [email protected] 'su -lc "cp -r '$location2' '$location1'";'
bash는 자동으로 문자열 연결을 수행합니다.
참고: 테스트되지 않았습니다. $locationX
공백이나 기타 이상한 문자가 포함되어 있으면 엉망이 될 수 있습니다.
답변3
Lesmana의 답변 외에도 두 번째 예에서는 변수를 인용해야 합니다.
sshpass -p "password" \
ssh [email protected] 'su -lc "cp -r '\\\"$location2\\\"' '\\\"$location1\\\"'";'
답변4
서비스를 업데이트하기 위해 제가 작성한 이 스크립트를 확인해 보세요.
PROJ=$2
원격 런타임 환경으로 전달됩니다.
function update-env () {
env=$1
proj=$2
# script for update test env
ssh -A root@$2.$1.test.com PROJ=$2 'bash -s' <<'ENDSSH'
# commands to run on remote host
su gmuser
cd /srv/apps/$PROJ
/usr/bin/git pull
exit
supervisorctl restart $PROJ
ENDSSH
}