web-dev-qa-db-ja.com

if条件でSSHはどのように機能しますか?

ファイルを計算し、最新の3つのファイルを除くすべてを削除するifステートメントがあります。しかし、このコマンドをリモートで実行したいと思います。 sshif条件と組み合わせるにはどうすればよいですか?

私はこれを試しましたが、成功しませんでした。

#!/bin/bash

ssh -t  [email protected] "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にアクセスできません:そのようなファイルまたはディレクトリはありません

8
Janith

注:実際には、この質問には2つの層があります。1つは「SSH経由でアクセス可能なリモートサーバーで重要なタスクを実行したい」です。もう1つは、「複雑なコマンドへの文字列、および引数は最終的に私が意図したものと異なることになります。」私は、使用されるアプローチが「正しい」かどうか(議論の余地がなく、エラーが発生しにくい、安全など)他の回答やコメントで示されているように、そうではないかもしれません。

コマンドラインはほとんど正しいです。引用符を少し変更するだけです。

主な問題は、二重引用符で囲まれた文字列がローカルシェルによって展開されるため、$(...)部分がローカルシステムで評価されることです。それらをリモートシステムに渡すには、スクリプトを一重引用符で囲む必要があります。

いくつかの引用符も埋め込まれています。元のスクリプトには、2つのechosの引数があります。外側の引用符を一重引用符に変更すると、awkスクリプトになります。これらの結果、引用符が省略され、echosを気にしませんが、大なり記号が出力のリダイレクトになるため、awkスクリプトが台無しになります。したがって、外側の引用符を一重引用符に変更した後、二重引用符に変更します。

これは引用符が修正されたスクリプトです。スクリプトには他の問題がある可能性があるため、構文を修正しました。

#!/bin/bash

ssh -t  [email protected] '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'
3
pt314

はい、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 [email protected] "$ssh_cmd"

この例では、bash here document を使用してコマンド文字列を生成します。いずれの場合でも、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"

globbing はローカルシステムでのみ発生するため、ls -t *.tgzは機能しません。また、ファイルのカウントにlsを使用することは、...などのエントリやディレクトリも返すため、お勧めできません。

10
Simon Sudler

この複雑なクォートの全体は、それを使用せず、代わりにスクリプトを使用するのに十分な証拠だと思います。複数のssh接続を避けたい場合は、スクリプトを他のホストにパイプして、1つのコマンドでそこで実行させます。

ローカルファイル、たとえば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 [email protected] \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh"

または( catの無駄な使用 を回避):

ssh -t [email protected] \
    "cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh" \
    < myscript.sh

これにより、ローカルスクリプトmyscript.shがリモート側にパイプされ、そこで(一時的な)ファイル/tmp/ms.shにリダイレクトされ、実行され、最終的に削除されます。

注:元のスクリプトのエラーをチェックしませんでしたが、アイデアを表示したかっただけです。エラーが発生しやすいクォートは必要なく、スクリプト内のすべてのコマンドはリモート側で実行されます。

4
PerlDuck

スクリプトをリモートインスタンスに配置し、sshを介して実行することをお勧めしますが、これを希望する方法で実行する方法を次に示します。

#!/bin/bash

Host='[email protected]'
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}が本当に必要かどうかはわかりませんが、追加することにしました。
3
pa4080