web-dev-qa-db-ja.com

フォルダとサブフォルダからファイルのみを再帰的にコピーするにはどうすればよいですか?

/homeフォルダーの下には、次のような多くのサブフォルダーがあります。

/home/user1
/home/user2/user_sub_2
/home/user3/user_sub_3/info_sub
/home/user4/INFO_FOLDER

/homeの下にあるすべてのファイルを再帰的に/tmp/calculationフォルダーにコピーします。すべてのファイルは、ターゲットフォルダに直接配置する必要があります(サブディレクトリは作成しないでください)。 2つ以上のファイルが同じ名前の場合、最後に変更されたファイルを/tmp/calculationにコピーする必要があります。

このアクションを実行するための正しいアプローチは何ですか?

2
yael
find /home ! -type d -exec bash -c '
    for pathname do
        if [ "$pathname" -nt "/tmp/calculation/${pathname##*/}" ]
        then
            cp "$pathname" /tmp/calculation
        fi
    done' bash {} +

これにより、/homeの下にあるすべての非ディレクトリファイルが検索され、これらのバッチの場合、短いbashスクリプトが呼び出されます。

短いbashスクリプトは、パス名の現在のバッチをループし、それぞれについて-ntテストを使用して、現在のファイルがターゲットディレクトリ内のコピーよりも新しいかどうか(またはコピーがそこに存在しないかどうか)をテストします。ターゲットディレクトリ内のファイルが古い場合、またはファイルが存在しない場合は、cpを使用して現在のファイルをターゲットディレクトリにコピーします。

パラメータ展開${pathname##*/}は、実際のファイル名の前にあるディレクトリパスを削除し、パス名のファイル名部分のみを残します。 $(basename "$pathname")に置き換えることができます。

関連:


ほとんど無関係:

-ntテストは非標準のテストです。これが、bashが呼び出す内部スクリプトにfindを使用することを選択した理由です。 sh -cの代わりにbash -cを使用すると、おそらくが機能しますが、テストのセマンティクスは、shになりすますシェル間でわずかに異なる場合があります。

たとえば、bashzsh、およびkshシェルでは、最初のオペランドに2番目のオペランドよりも新しい変更タイムスタンプがある場合、-ntテストはtrueになります。または、第2オペランドが存在しない場合。

ただし、dashシェルでは、両方のファイルがほとんど存在し、テストを行うには、最初のファイルが2番目のファイルよりも新しい必要があります。 true(ドキュメントによる)。この場合、この違いは問題になりませんでした。

yashシェルでは、どちらかのファイルが存在しない場合に何が起こるかはマニュアルで指定されていません。

したがって、非標準の機能を使用する場合は、特定のシェルを使用するのが最も安全です。この特定の場合、おそらくsh -cで機能したとしてもです。とにかく。

(このインスタンスでbashを使用した場合のdownsideは、比較するタイムスタンプの解像度が1秒しかないことですが、それは別の話)

5
Kusalananda

以下のコマンドで試してみましたが、うまくいきました

for file in `find /home -type f | awk -F "/" '{print $NF}'`
do
    for dir in `find . -type d| sed "s/\.//g"| sed 's/$/\//g'`
    do
        Sudo find $dir -type f -iname $file | awk '{print "ls -ltrh" " " $0}'
    done | sh | sed -n '$p'
done | awk '{print "cp -rvfp" " " $NF " " "/destinationlocationtocopy/"}' | sh
0