単にコピーするのではなく、各ファイルにコマンドを適用してディレクトリ構造を複製しますか?

単にコピーするのではなく、各ファイルにコマンドを適用してディレクトリ構造を複製しますか?

時間が経つにつれて、私は何度も同じパターンに遭遇しました。ある種のディレクトリ構造があります。

example/
├── a
│   └── c
│       ├── d.txt (120k)
│       └── e.txt (60k)
└── b
    └── f.txt (280k)

そして、たとえば のexample_grepped代わりとして各コマンドを適用して、ファイルを別のディレクトリに「コピー」したいとします。その結果、 でフィルターされたファイルを含む同じ構造のフォルダーが作成されます。cpgrep ERRORgrep

example_grepped/
├── a
│   └── c
│       ├── d.txt (1k)
│       └── e.txt (0b)
└── b
    └── f.txt (12k)

メディア ファイルの変換 (FLAC から MP3、PNG から JPG) も同じパターンですが、今回はビルド プロセスの一部として異なるスキーマ形式を変換する場合です。

使用できる汎用コマンドはありますか? またはのようなものですfoobar example example_grepped --command 'grep ERROR'foobar flacs mp3s --command 'ffmpeg -i {} {}.mp3'?

おそらく、あまり知られていないxargsフラグでしょうか?(findパイプで通すxargsほとんど十分ですが、ほとんどすべてのコマンドでは、ディレクトリ構造がすでに存在していることを前提としています。

答え1

ディレクトリ構造を個別に再作成せずに私が見つけた最も近い答えは、インストール:

cd example
find . -type f -exec sh -c 'grep ERROR {} | install -D /dev/stdin /tmp/example_grepped/{}' \;

残念ながら、上記はコマンドが結果を STDOUT にスローできる場合にのみ機能します。

答え2

これにアプローチする別の方法は、とにかく再帰コピーを行うプログラムを使用することです。 を確認しましたrsyncが、ざっと見ただけではコールバック オプションは見つかりませんでした。しかし、gnu には、ファイルの入力を に取得するコマンドを実行できるtarオプションがあります。しかし、その場合、ファイルを作成するにはどうすればよいでしょうか。 というコマンドは、 内の現在のファイル名を検索します。--to-commandstdin$TAR_FILENAME

すべてをまとめると、基本的な呼び出しは次のようになります

tar cf - example | tar xf - --to-command="./script example_grepped 'grep-pattern'"

ここでのスクリプトは次のようになります

#!/bin/bash
mkdir -p $(dirname "$1/$TAR_FILENAME")
grep '$2' >"$1/$TAR_FILENAME"
exit 0

これを解決する別の方法としては、コマンド ラインでコマンドを実行するスクリプトで tar パイプをラップする方法があります。ただし、このmkdir ...dirname構造のエスケープは少し難しいでしょう。

答え3

#!/bin/bash

filter() {

    local target_root="${@: -1}"

    target_path=$(sed -E "s/[^/]*/$target_root/" <<< "$1")
    target_dir=$(dirname "$target_path")

    mkdir -p "$target_dir"

    if [[ -f $1 ]]; then
        # do your grep thing here
        grep burger "$1" > "$target_path"
    fi
}

export -f filter
source_root="example"
target_root="example_grepped"

find "$source_root/" -print0 | xargs -0 -I content bash -c "filter 'content' '$target_root'"

このスクリプトは、スペースを含むディレクトリ名やファイル名でも機能します。

ソース ディレクトリ (「example」) がある場所でこのスクリプトを実行します。

答え4

GNU Parallel を使用すると、次のようなことができます。

cd src
find . -type f | parallel 'mkdir -p ../dst/{//}; dostuff --input {} --output ../dst/{}'

関連情報