ファイルを計算し、最新の3つのファイルを除くすべてを削除するif
ステートメントがあります。しかし、このコマンドをリモートで実行したいと思います。 ssh
をif
条件と組み合わせるにはどうすればよいですか?
私はこれを試しましたが、成功しませんでした。
#!/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にアクセスできません:そのようなファイルまたはディレクトリはありません
注:実際には、この質問には2つの層があります。1つは「SSH経由でアクセス可能なリモートサーバーで重要なタスクを実行したい」です。もう1つは、「複雑なコマンドへの文字列、および引数は最終的に私が意図したものと異なることになります。」私は、使用されるアプローチが「正しい」かどうか(議論の余地がなく、エラーが発生しにくい、安全など)他の回答やコメントで示されているように、そうではないかもしれません。
コマンドラインはほとんど正しいです。引用符を少し変更するだけです。
主な問題は、二重引用符で囲まれた文字列がローカルシェルによって展開されるため、$(...)
部分がローカルシステムで評価されることです。それらをリモートシステムに渡すには、スクリプトを一重引用符で囲む必要があります。
いくつかの引用符も埋め込まれています。元のスクリプトには、2つのecho
sの引数があります。外側の引用符を一重引用符に変更すると、awkスクリプトになります。これらの結果、引用符が省略され、echo
sを気にしませんが、大なり記号が出力のリダイレクトになるため、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'
はい、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
を使用することは、.
、..
などのエントリやディレクトリも返すため、お勧めできません。
この複雑なクォートの全体は、それを使用せず、代わりにスクリプトを使用するのに十分な証拠だと思います。複数の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
にリダイレクトされ、実行され、最終的に削除されます。
注:元のスクリプトのエラーをチェックしませんでしたが、アイデアを表示したかっただけです。エラーが発生しやすいクォートは必要なく、スクリプト内のすべてのコマンドはリモート側で実行されます。
スクリプトをリモートインスタンスに配置し、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}
が本当に必要かどうかはわかりませんが、追加することにしました。