別のLinuxサーバーからリモートでファイルハッシュを取得しようとします。

別のLinuxサーバーからリモートでファイルハッシュを取得しようとします。
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...)パラメータを使用します。で実行します。zshtcshfishyashbashrc

  • 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

md5sum1つの引数で実行されるコマンドでは、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

おすすめ記事