while IFS= read -r line
do
LOCATION=$(echo "$line" | awk 'BEGIN { FS = "," } ; { print $1 }')
USER=$(echo "$line" | awk 'BEGIN { FS = "," } ; { print $2 }')
MD5=$(echo "$line" | awk 'BEGIN { FS = "," } ; { print $3 }')
FILE=$(echo "$line" | awk 'BEGIN { FS = "," } ; { print $4 }')
CHECK=$(md5sum "$FILE" | awk '{ print $1 }')
FILENAME="${FILE##*/}"
echo "$FILENAME"
REMOTECHECK=$(ssh server md5sum filelocation/"${FILENAME}" < /dev/null | awk '{ print $1 }')
if [[ "$CHECK" == "$MD5" ]]; then
echo "Local File MD5: "
echo "$CHECK"
echo "Remote File MD5: "
echo "$REMOTECHECK"
fi
done < _path to file_
空白のないファイル名にはスクリプトが正しく機能しますが、ファイル名に空白が含まれていると問題が発生します。
ファイル名に空白があるときに出力されます。
md5sum: path_to_file/File: No such file or directory
md5sum: Name: No such file or directory
md5sum: With: No such file or directory
md5sum: Spaces.mp4: No such file or directory
私が知る限り、問題はこのコード行にあります。
REMOTECHECK=$(ssh server md5sum filelocation/"${FILENAME}" < /dev/null | awk '{ print $1 }')
上記のスクリプトは、空白のないファイル名に対して機能し、問題は空白のあるファイル名でのみ発生します。
どんなアドバイスでも提供していただければとても役に立ちます。
ベストアンサー1
ssh
実行されない注文するリモートホストは、リモートユーザーのログインシェルが解釈できるようにコードを送信します。したがって、リモートシェルに指定された引数リストを使用して特定のコマンドを実行させるには、次の手順を実行する必要があります。それシェル構文は、シェルにこれらのパラメータを使用してコマンドを実行させるようにします。
シェルはコマンドラインソルバーです。主な目的は、コマンドラインから与えられたコマンドを実行することです(コマンドラインは言い換えれば、シェル構文のコード)あなたはそれを提供します。値$FILENAME
が Korn のようなシェルでは、コマンドラインは次のようFile Name With Spaces.mp4
になります。
ssh server md5sum filelocation/"${FILENAME}"
シェルの作業は、次のパラメータを使用して名前付き$PATH
ファイルを実行することです。ssh
/usr/bin/ssh
argv[0]
:ssh
argv[1]
:server
argv[2]
:md5sum
argv[3]
:filelocation/File Name With Spaces.mp4
シェル言語構文では、$xxx
スペースはコマンドパラメータを区切ってパラメータ拡張をトリガします。
その後、アクションはssh
受け取った引数のリストから連結server
し、残りの引数を空白で連結し、結果をリモートユーザーのログインシェルに渡すことです(それらは変更されたデフォルトのシェルを使用できますが、、、、chsh
...)パラメータを使用します。で実行します。zsh
tcsh
fish
yash
bash
rc
argv[0]
: そのシェルの名前argv[1]
:-c
argv[2]
:結果、ここ:md5sum filelocation/File Name With Spaces.mp4
ここではすべてのシェルの構文が異なりますが、コマンドラインはほとんどの人が同じように解釈するのと同じくらい簡単です。つまり、/path/to/md5sum
次のパラメーターを使用してコマンドを実行します。
argv[0]
:md5sum
argv[1]
:filelocation/File
argv[2]
:Name
argv[3]
:With
argv[4]
:Spaces.mp4
md5sum
1つの引数で実行されるコマンドでは、filelocation/File Name With Spaces.mp4
これらのスペースが引数区切り文字と見なされないことをリモートシェルに知らせる必要があります。これは引用/エスケープを通じて行われます。そして引用構文はシェルによって大きく異なります。
とにかく、空白だけが問題を引き起こす唯一の文字ではありません。リモートシェル構文の特殊文字も問題になります。たとえば、ファイル名が$(reboot).mp4
またはその場合、blah;rm -rf ~;blah.mp4
より大きな問題があります。
リモートシェルがBourneに似ていることがわかっている場合は、次のことができます。
#! /bin/zsh -
while IFS=, read -ru3 location user md5 file rest; do
md5sum -- $file | read check rest
filename=$file:t
print -r -- $filename
ssh -n server "md5sum filelocation/${(qq)filename}" | read remotecheck rest
if [[ $md5 = $check ]]; then
printf '%s File MD5: %s\n' Local "$check" Remote "$remotecheck"
fi
done 3< $path_to_file
${(qq)file}
次に見積もり一重引用符は、Bourneのようなシェルから内容を引用する最も安全な方法です。。したがって、あなたの場合はにFile Name With Spaces.mp4
転送されます'File Name With Spaces.mp4'
。そうでFile Name With Quote's.mp4
あれば、引用されたもの自体を除いてすべてが'File Name With Quote'\''s.mp4'
引用されます。'...'
'
\
Bourneに似たリモートシェルが保証されていない場合は、以下を参照してください。リモートユーザーのログインシェルを知らず、SSHを介して任意の単純なコマンドをどのように実行できますか?より多くの選択のために。
md5sum
ここで特定のユースケースでは、ローカルとリモートのチェックサムを比較するためのもう1つのオプションは、確認モード(と一緒に)を使用することです-c
。
#! /bin/zsh -
while IFS=, read -ru3 location user md5 file rest; do
(cd -P -- $file:h && md5sum -- $file:t) |
ssh -n server 'cd ./filelocation && md5sum -c'
done 3< $path_to_file
今回はファイル名がローカルに作成され、md5sum
リモートファイルの標準入力から読み取られるため、リモートシェルでそれを参照する必要はありません。このコマンドラインはほとんどのシェルで理解されていますcd ./filelocation && md5sum -c
(接頭辞は、./
非対話式またはsshを介して呼び出されたときにrcファイルを読み書きできるcsh / tcsh / bashでの影響を避けるためです)。$cdpath
$CDPATH