1

私は、Bash スクリプト (OSX 上) を少し手伝ってもらっています。ソース フォルダーとターゲット フォルダーの 2 つのパラメーターを受け取り、ソース階層内のすべてのファイルをチェックして、それらがターゲット階層に存在するかどうかを確認するスクリプトを作成したいと考えています。つまり、データ DVD を指定して、そこに含まれるファイルが既に内部ドライブにあるかどうかを確認します。

私がこれまでに思いついたのは

#!/bin/bash

if [ $# -ne 2 ]
then
        echo "Usage is command sourcedir targetdir"
        exit 0
fi

source="$1"
target="$2"

for f in "$( find $source -type f -name '*' -print )"
do

パスなしでファイル名を取得し、それが存在するかどうかを確認する方法が最善かどうかはわかりません。私は本当にスクリプトの初心者です。

編集:これまでに与えられた答えはすべて、コンパクトなコードに関して非常に効率的です。ただし、ターゲット階層内の任意のソース階層全体で見つかったファイルを検索できる必要があります。見つかった場合は、チェックサムと最終更新日などを比較してコメントしたいと思います。見つからない場合は、これに注意したいと思います。目的は、外部メディア上のファイルがファイル サーバーにアップロードされているかどうかを確認することです。

4

3 に答える 3

1

$source_dirに存在しないのファイルのみを一覧表示するには$target_dir:

 comm -23 <(cd "$source_dir" && find .|sort) <(cd "$target_dir" && find .|sort)

コマンドなど-fを使用して、通常のファイルのみに制限できます。find

このcommコマンド (「共通」の略) は、2 つのテキスト ファイル間で共通する行を見つけ、3 つの列を出力します。最初のファイルの行のみ、2 番目のファイルの行のみ、両方に共通の行です。数字は対応する列を抑制するため、出力はcomm -23最初のファイルからの行のみで、2 番目のファイルには表示されません。

プロセス置換構文<(command)は、指定されたコマンドの出力に接続された名前付きパイプへのパス名に置き換えられます。これにより、stdin と stdout だけでなく、ファイル名を配置できる場所ならどこでも「パイプ」を使用できます。

この場合のコマンドは、2 つのディレクトリの下にファイルのリストを生成します。 は、cd比較対象のディレクトリに相対的な出力を作成するため、対応するファイルは同一の文字列として出力され、 は、リストされている同じファイルによって混乱sortcommないようにします。 2 つのフォルダーの順序が異なります。

于 2012-08-31T23:44:18.073 に答える
1

これにより、いくつかのアイデアが得られるはずです。

#!/bin/bash

DIR1="tmpa"
DIR2="tmpb"

function sorted_contents
{
    cd "$1"
    find . -type f | sort
}

DIR1_CONTENTS=$(sorted_contents "$DIR1")
DIR2_CONTENTS=$(sorted_contents "$DIR2")

diff -y  <(echo "$DIR1_CONTENTS") <(echo "$DIR2_CONTENTS")

私のテストディレクトリでは、出力は次のとおりです。

[user@host so]$ ./dirdiff.sh
./住所録.dat ./住所録.dat
./passwords.txt ./passwords.txt
./some-song.mp3 <
./聖杯.info ./聖杯.info
                                             > ./勝利.wav
./zzz.wad ./zzz.wad

明確でない場合、「some-song.mp3」は最初のディレクトリのみにあり、「victory.wav」は2番目のディレクトリのみにありました。残りのファイルは共通でした。

これは内容ではなく、ファイル名のみを比較することに注意してください。これがどこに向かっているのが好きなら、diffオプションで遊ぶことができます(おそらく--suppress-common-lines、よりきれいな出力が必要な場合)。

しかし、これはおそらく私がそれにアプローチする方法です-多くの作業を にオフロードしdiffます。

編集:次のような単純なことも指摘する必要があります。

[user@host so]$ diff tmpa tmpb

も機能します:

    tmpa のみ: some-song.mp3
    tmpb のみ: win.wav

...しかし、自分でスクリプトを作成するほどの満足感は得られません。:-)

于 2012-08-31T23:04:17.700 に答える
0

行に関するいくつかのコメントfor f in "$( find $source -type f -name '*' -print )":

  • それを作る"$source"。変数置換は必ず二重引用符で囲んでください。それ以外の場合、結果はワイルドカード パターンとして扱われる単語に分割されます (シェルの解析規則における歴史的な奇妙さ)。特に、変数の値にスペースが含まれている場合、これは失敗します。
  • その方法の出力を反復することはできませんfind$f二重引用符があるため、からの完全な出力を含むループを 1 回繰り返すことになりますfind。二重引用符がないと、ファイル名にスペースやその他の特殊文字が含まれていると、スクリプトがトリップします。
  • -name '*'ノーオペレーションであり、すべてに一致します。

私が理解している限りでは、ファイルの場所とは関係なく、名前でファイルを探したいと考え/dvd/path/to/somefileています。つまり、/internal-drive/different/path-to/somefile. したがって、名前でインデックス付けされた両側のファイルのリストを作成します。find少しの出力をマッサージすることでこれを行うことができます。以下のコードは、改行を除くファイル名の任意の文字を処理できます。

list_files () {
  find . -type f -print |
  sed 's:^\(.*\)/\(.*\)$:\2/\1/\2:' |
  sort
}
source_files="$(cd "$1" && list_files)"
dest_files="$(cd "$2" && list_files)"
join -t / -v 1 <(echo "$source_files") <(echo "$dest_files") |
sed 's:^[^/]*/::'

このlist_files関数は、パスを含むファイル名のリストを生成し、ファイルの前にファイル名を追加します。たとえば/mnt/dvd/some/dir/filename.txtfilename.txt/./some/dir/filename.txt. 次に、ファイルを並べ替えます。

このコマンドは、ソース階層で呼び出されたファイルがあり、宛先階層では呼び出されていない場合のjoinように、行を出力します。行頭にファイル名が必要なくなったので、最後に出力を少し修正します。filename.txt/./some/dir/filename.txtfilename.txt

于 2012-09-01T01:16:42.850 に答える