SSHを介してローカル変数に格納されているディレクトリにアクセスできます$out_dir
。しかし、なぜこのfind | head
コマンドが機能しないのかわかりません。存在する試み #2、コマンドの最後に2番目のバックスラッシュを追加しましたfind
。
試行#1エラー: find: `/dir/on/remote/server': No such file or directory
ssh $user@$ip << EOF
discard=$( find $out_dir -exec basename {} \; | head -n -1 )
for f in $discard; do
echo "rm $f"
done
logout
EOF
試み #2 エラー: syntax error near unexpected token `|'
ssh $user@$ip << EOF
discard=$( find $out_dir -exec basename {} \\; | head -n -1 )
for f in $discard; do
echo "rm $f"
done
logout
EOF
答え1
試行#1で「ファイルまたはディレクトリがありません」というメッセージが表示されるのは、<<EOF
heredoc(the)のすべての変数とコマンド補間がリモートホストに送信される前にローカルで実行されるためです。
正しく気づいたように$out_dir
補間が進んでいます。見たいディレクトリが表示されます。これはSSH呼び出しを行う前にローカルコンピュータで発生します。コマンドの置き換え($()
)もローカルで発生します(ただしリモートで実行しようとしています)。つまり、全体の検索結果は、リモートコンピュータに送信される前にローカルに処理されます。ここに含まれるすべての内容は$()
heredocによって処理されます。したがって、${out_dir}
ローカルコンピュータには存在しないようです。 「該当するファイルやディレクトリはありません。」
これをよりよく理解したい場合は、この例を単純化してみましょう。この試み:
$ ssh foo@localhost <<EOF
echo "using account: $(whoami)"
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.
<truncated>
using account: vagrant
私のローカルアカウントは「vagrant」なので、明らかに$()の内容はローカルで実行されます。正常に機能した場合、アカウントは「foo」になりますssh foo@localhost
。
";"代わりに「\」をエスケープしたため、試行#2が中断されました。 Findを-exec
終了する必要がありますが、今ではありません。代わりに、コマンドは突然、bashコマンドを終了する吊り下げ";"で終了します。 '|'は一部の入力が渡されると予想していますが、何も指定されていません。効果的に以下を生成します。
$ | cat
-bash: syntax error near unexpected token `|'
それでは、考えられる解決策は何ですか?
まあ、find
削除することができます:
ssh $user@$ip <<EOF
find $out_dir -delete
EOF
シンプルでシンプルです。特定のファイルを選択して他のファイルを除外することを心配している場合find
。
find
現在のバージョンでは、いくつかの極端なケースを処理しようとしているので、"修正"提案を提供します。
- デフォルト名の使用
- 何かの目的を指します。
head -n -1
しかし、私はこれがあなたが期待するように働くとは思わない。
まず、呼び出しはbasename
ほとんどのパスを削除し、sshコマンドでディレクトリを変更するために何もしません。 SSH実行は、$ {user}の家に関連するすべてを削除しようとします。 ${out_dir}を指定するときに家以外のディレクトリを使用したいようです!今回もfind
削除作業を行ってみましょう。
第二に、私は誤解しているかもしれませんが、ターゲットhead -n -1
ファイルのリストから$ {out_dir}を削除したことがあるようです。
$ find junk/
junk/
junk/one
junk/two
junk/three
そうですね。を削除したくありませんjunk/
。
ただし、次のことを試してください。
$ seq 1 4
1
2
3
4
$ seq 1 4 | head -n -1
1
2
3
最初の行は保持されず、最後の行は維持されます。尾を試してみてください:
$ seq 1 4 | tail -n +2
2
3
4
しかし、もう一度申し上げますが、find
それを取り除くのを手伝います。
ファイルの削除のみが必要な場合は確認してください-type f
。ただし、高度なフィルタリング用の除外モードと埋め込みモードもあります。
答え2
この試み:
ssh "$user@$ip" "out_dir=$out_dir;" '
discard=$( find $out_dir -exec basename {} \; | head -n -1 )
for f in $discard; do
echo "rm $f"
done
'
メモ:意図したリモートコマンドをより簡単で安全にすることができますが、これについて少し言うと、ポイントはあいまいになります。
デフォルトでは、次のセクションを通過する必要があります。ㅏ)しなければならない返品次に展開地元の機械とそのもの雨)しなければならないただ次に展開離れて機械炉分離sshパラメータの場合、前者には二重引用符を使用し、後者には一重引用符を使用します。
-c
sshはすべての「コマンド」引数を空白で連結し、それをリモートシステム上のユーザーログインシェルのオプションに単一の引数として渡します。
リモートコマンド自体に一重引用符を含める必要がある場合は、コマンドの置き換え+ドキュメントここで組み合わせを使用できます。また、「ローカル」変数の値にスペースやその他の特殊文字を含めることができる場合は、エスケープする必要があります。
out_dir='/path/to/ * happiness * '
out_dir=$(printf %s "$out_dir" | sed 's/[^a-zA-Z0-9_/.]/\\&/g')
ssh localhost out_dir="$out_dir;" "$(cat <<'EOT'
echo '<$out_dir>' = "<$out_dir>"
EOT
)"
<<'EOF'
;の一重引用符が省略されている場合は、$out_dir
ここの文書で拡張されます(ローカルコンピュータで)。
bashの最新バージョンは次の形式を持っているので、醜い形式の代わりに${var@Q}
簡単に使用できます。"out_dir=${outdir@Q};"
echo | sed
標準入力を介してリモートスクリプトを渡すことはほとんど必要ありません。