SSH는 if 조건에서 어떻게 작동합니까?


8

나는이 if파일을 계산하고 최신의 세 개의 파일을 제외하고 모두 삭제하는 문을. 그러나이 명령을 원격으로 실행하고 싶습니다. 조건 ssh과 어떻게 결합 할 수 if있습니까?

나는 이것을 시도했지만 성공하지 못했습니다.

#!/bin/bash

ssh -t  test@192.168.94.139 "cd /var/www/test.com/backup ;

if [ $(ls  | wc -l) -lt 3  ]
then
    echo "Less"
else [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]
    echo "deleted"
fi"

내가 얻은 오류 :

ls : * .tgz에 액세스 할 수 없음 : 해당 파일 또는 디렉토리가 없습니다.


그렇다면 어떻게 이것을 사용자 정의 할 수 있습니까?
Janith

왜 그런가요? 명령은 따옴표 안에 있습니다.
궤도에서 가벼움 경주

2
$( )명령 의 일부는 명령을 시작하기 전에 로컬 쉘에 의해 실행됩니다 ssh. 그 사실을 모두하는 경우 $( )가에 의해 둘러싸인 때 단독으로뿐만 아니라 의미 "의. 그러나 $( )내부에 있으면 '로컬 셸에서 실행되지 않습니다.
kasperd

답변:


3

참고 : 여기에는 실제로 두 가지 층이 있습니다. 하나는 'SSH를 통해 액세스 가능한 원격 서버에서 사소한 작업을 실행하고 싶습니다'입니다. 다른 하나는 '복잡한 문자열을 명령에 전달하려고하는데 인수가 의도 한 것과 다릅니다.'입니다. 나는 사용 된 접근 방식이 높은 수준의 문제를 해결하는 데 "적절한"(편리하고 오류가 발생하지 않는 보안 등) 여부에 대해 논의하지 않고 하위 수준의 질문에 대답하고 있습니다. 다른 답변과 의견에서 알 수 있듯이 그렇지 않을 수도 있습니다.

당신의 커맨드 라인은 대부분 맞습니다; 인용 부호를 조금만 변경하면됩니다.

큰 문제는 큰 따옴표로 묶인 문자열이 로컬 셸에 의해 확장되므로 $(...)부품이 로컬 시스템에서 평가된다는 것입니다. 원격 시스템으로 전달하려면 스크립트를 작은 따옴표로 묶어야합니다.

또한 따옴표가 포함되어 있습니다. 원래 스크립트에는 두 가지에 대한 인수가 있습니다 echo. 외부 따옴표를 작은 따옴표로 변경하면 awk 스크립트가됩니다. 이 효과적으로 인용 부호가 생략되어 echos를 귀찮게하지 않지만 보다 큰 부호가 출력 리디렉션이되므로 awk 스크립트가 엉망이됩니다. 따라서 외부 인용 부호를 작은 따옴표로 변경 한 후 큰 따옴표로 변경하십시오.

인용이 수정 된 스크립트입니다. 스크립트에 다른 문제가있을 수 있습니다. 구문을 수정했습니다.

#!/bin/bash

ssh -t  test@192.168.94.139 'cd /var/www/test.com/backup ;

if [ $(ls  | wc -l) -lt 3  ]
then
  echo "Less"
else [ $(ls -t *.tgz|awk "NR >3"|xargs rm -f) ]
  echo "deleted"
fi'

/var/www/test.com/backup"BACKUPDEST"라는 변수 에 할당하고 싶습니다. cd $BACKUPDEST이 작업을 수행하는 방법을 알려주시겠습니까?
Janith

1
어디에 값을 할당 BACKUPDEST합니까? 원격에서 발생하면 스크립트에 정상적으로 포함하십시오. 로컬로 설정하려면 (예를 들어 로컬 스크립트에서 계산하거나 명령 줄 인수로 전달) 첫 번째 줄을 예를 들어 다음과 같이 변경할 수 있습니다 "cd $BACKUPDEST"' ;-쉘은 큰 따옴표 부분을 확장하고 작은 따옴표를 유지합니다 부분 그대로, 둘을 연결하고 결과를에 마지막 인수로 전달합니다 ssh.
pt314

어, 있는지 확인 "cd '$BACKUPDEST'"' ;하는 경우에 해당 변수의 경로는 약간의 불확실성 (예 : 공백)가 포함되어 있습니다. 다시 말하지만, 이런 식으로 할 수 있다고 말하는 것이 아니라 이런 식으로 할 수 있다고 말하는 것입니다.
pt314

10

예, 다음을 통해 복잡한 스크립트를 실행할 수 있습니다 ssh

#!/bin/bash -e

ssh_cmd="$(cat <<-EOF
    cd /var/www/test.com/backup;

    if [ \$(ls  | wc -l) -lt 3  ]; then
        echo "less"
    elif [ \$(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
        echo "deleted"
    else
        echo "something else"
    fi
EOF
)"

ssh -t test@192.168.94.139 "$ssh_cmd"

이 예제는 bash here 문서 를 사용하여 명령 문자열을 생성합니다. 어쨌든 ssh를 통해 스크립트를 전달하는 것은 변수의 인용 및 탈출이 어렵 기 때문에 오류가 발생하기 쉽습니다 (명령 전에 백 슬래시를 명심하십시오). 스크립트가 너무 복잡해지면이를 통해 복사 scp한 다음 대상 호스트에서 실행하는 것이 좋습니다 .

스크립트를 수정하지 않았지만 다음은 원격 호스트에서 계산 및 삭제가 작동하는 방법에 대한 예입니다.

#!/bin/bash -e

tmp_dir="$(mktemp -d)"

ssh_cmd="$(cat <<-EOF
    cd "$tmp_dir"

    cnt_tgz=(\$(find . -type f -name "*.tgz"))
    if [[ \${#cnt_tgz[@]} -lt 3 ]]; then
        echo "less"
    else
        rm "\${cnt_tgz[@]}"
        echo "deleted"
    fi
EOF
)"

touch "$tmp_dir/1.tgz"
ssh -t localhost "$ssh_cmd"
touch "$tmp_dir/2.tgz" "$tmp_dir/3.tgz"
ssh -t localhost "$ssh_cmd"

로빙 은 로컬 시스템에서만 발생 ls -t *.tgz하므로 작동하지 않습니다 . 또한 파일 수 계산에 사용 하는 것은 좋지 않습니다. 왜냐하면 , 및 디렉토리와 같은 항목도 반환하기 때문 입니다.ls...


오류가 발생했습니다. syntax error near unexpected token elif',elif [ $(ls -t |awk 'NR >3'|xargs rm -f) ]; then'
Janith

;주먹 진술에 누락 이있었습니다 . 그러나 나는 당신에게 스크립트를 고치지 않았습니다! 많은 문제는이 예입니다ls *.tgz
사이먼 Sudler

1
"글 로빙은 로컬 시스템에서만 발생하기 때문에 ls -t * .tgz가 작동하지 않습니다." -올바르게 탈출하면 원격 시스템에서 발생합니다. 원래 버전은 $(...)큰 따옴표로 묶인 문자열 안에 알몸 이므로 로컬 셸에서이를 평가했습니다. \$(...)첫 번째 예제에서 보듯이 이스케이프 하거나 전체 스크립트 주위에 작은 따옴표를 사용하면 로컬 셸이 확장되지 않으므로 원격 셸로 확장되어 원격 셸에 의해 확장되고 스크립트가 작동합니다. 의도 한대로.
pt314

이것은 here 문서 대신 작은 따옴표를 사용 하는 것이 좋습니다. 삽입하려는 변수가 있더라도 작은 따옴표로 묶은 문자열 printf을 사용하고 변수를 확장하는 것이 좋습니다. 모든 셸 변수를 이스케이프 처리하는 것보다 관리하기가 더 쉽습니다. 또한 cathere 문서를 변수로 캡처하는 데 사용할 필요가 없습니다 !
Daniel Pryden

4

이 복잡한 인용문은 그것을 사용하지 않고 스크립트를 대신 사용하기에 충분한 증거라고 생각합니다. 여러 ssh연결 을 피 하려면 스크립트를 다른 호스트로 파이프하고 하나의 명령으로 실행하십시오.

로컬 파일 myscript.sh:

cd /var/www/test.com/backup;

if [ $(ls  | wc -l) -lt 3  ]; then
    echo "less"
elif [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
    echo "deleted"
else
    echo "something else"
fi

그때:

cat myscript.sh | \
    ssh -t test@192.168.94.139 \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh"

또는 (무의미한 고양이 사용을 피하십시오 ) :

ssh -t test@192.168.94.139 \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh" \
    < myscript.sh

로컬 스크립트 myscript.sh를 원격으로 파이프하여 스크립트 를 (임시) 파일로 리디렉션하고 /tmp/ms.sh, 실행 한 다음 마지막으로 제거합니다.

참고 : 원본 스크립트에서 오류를 확인하지 않았지만 아이디어를 보여주기를 원했습니다. 오류가 발생하기 쉬운 인용이 필요하지 않으며 스크립트의 모든 명령이 원격에서 실행됩니다.


스크립트를 임시 파일로 저장할 필요가 없으며 적절한 쉘로 파이프하십시오 ssh user@host bash <myscript.sh.
pt314

2
그러나 스크립트 자체가 표준 입력에서 읽지 않으려는 경우에만 리디렉션이 작동한다는 점에 유의하십시오.
chepner


예, 리디렉션에는 제한이 있습니다. 또한 예측 가능한 이름의 임시 파일 작성 (및 실행)과 관련된 많은 보안 문제를 피합니다. 선택 또는 필요에 따라 임시 스크립트를 사용하는 경우 mktemp또는 유사한 안전한 것을 사용하여 작성하십시오 .
pt314

3

원격 인스턴스에 스크립트를 배치하고 ssh를 통해 스크립트를 실행하는 것을 선호하지만 원하는 방식으로이를 수행 할 수있는 방법은 다음과 같습니다.

#!/bin/bash

HOST='test@192.168.94.139'
REMOTE_PATH='/var/www/test.com/backup'

COMMAND1="ssh \"$HOST\" 'ls \"$REMOTE_PATH\" | wc -l'"
COMMAND2="ssh \"$HOST\" 'ls -t \"$REMOTE_PATH\"/*.tgz'"
COMMAND3="xargs ssh \"$HOST\" rm -rf"

if [[ $(eval "$COMMAND1") -le 3 ]]
then
    echo "Less"
else
    eval "$COMMAND2" | awk 'NR > 3' | eval "$COMMAND3" && echo "Deleted"
fi

노트:

  • 조건식 -lt이로 대체됩니다 -le.
  • eval -인수를 연결하여 명령을 구성하십시오.
  • 표현식 \"내에서 이러한 추가 따옴표가 실제로 필요한지 확실하지 않지만 따옴표 $COMMAND{1..3}를 추가하기로 결정합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.