複製目錄結構,對每個檔案應用命令,而不是簡單地複製它?

複製目錄結構,對每個檔案應用命令,而不是簡單地複製它?

隨著時間的推移,我一次又一次遇到相同的模式:我有某種目錄結構:

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

我想將文件“複製”到另一個目錄,例如,example_grepped對每個文件應用一個命令,就像代替cp- 比如說,grep ERROR這樣說,我最終得到一個具有相同結構的文件夾,但文件通過grep

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,但快速瀏覽後找不到回調選項。但是 gnutar有一個選項--to-command,您可以提供一個要運行的命令,將文件的輸入獲取到stdin.但是如何建立文件呢?好吧,呼叫的命令會尋找 中的目前檔名$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/{}'

相關內容