디렉토리 구조를 복사하고, 단순히 복사하는 대신 각 파일에 명령을 적용하시겠습니까?

디렉토리 구조를 복사하고, 단순히 복사하는 대신 각 파일에 명령을 적용하시겠습니까?

시간이 지나면서 나는 같은 패턴을 반복해서 겪었습니다. 일종의 디렉터리 구조가 있었습니다.

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잠깐 살펴본 후에도 콜백 옵션을 찾을 수 없습니다. 하지만 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'"

이 스크립트는 공백이 포함된 디렉터리 및 파일 이름에도 작동합니다.

소스 디렉터리("examples")가 있는 곳에서 이 스크립트를 실행하세요.

답변4

GNU Parallel을 사용하면 다음과 같은 작업을 수행할 수 있습니다.

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

관련 정보