foo
파일 경로를 사용하고, 파일을 읽고, 일부 변경 사항을 적용하고, 변경된 파일을 표준 출력으로 출력하는 스크립트를 작성했습니다 .
foo src/file.foo > dest/file.changed.foo # works fine
cat src/file.foo | foo > dest/file.changed.foo # also works fine
이제 이 명령을 디렉터리의 여러 파일에 적용하고 각 파일에 대해 다음을 수행하려고 합니다.
src/file.foo --> foo --> 대상/file.changed.foo
find src -name '*.foo' \
-exec bash -c 'for x; do dest=${x/src/dest}; foo ${x} > ${dest/\.foo$/.changed.foo}; done' _ {} +
위의 방법은 효과가 있지만 문제는 일상적으로 사용하기에는 너무 복잡하다는 것입니다.더 쉬운 방법은 없을까요?foo
일을 복잡하게 만드는 방식이 아닐까 싶습니다 .
답변1
재귀 와일드카드를 사용하면 입력과 조작이 훨씬 줄어듭니다. 배쉬에서는 다음을 입력하세요.shopt -s globstar
당신의 .bashrc
. ksh93에서는 재귀 와일드카드가 필요합니다 set -o globstar
. zsh에서는 기본적으로 사용할 수 있습니다. Bash에서 재귀 와일드카드는 디렉터리에 대한 심볼릭 링크에서도 재귀됩니다.
문자열 작업을 저장하려면 먼저 소스 트리의 상단(또는 대상 트리의 상단)으로 변경합니다.
cd foo
for x in **/*.foo; do foo "$x" >"../dest/${x%.*}.changed.foo"; done
파일 이름에 공백이나 와일드카드가 포함되지 않은 경우 큰따옴표를 생략할 수 있습니다.
zsh에서는 큰따옴표가 필요하지 않으며 현재 디렉토리를 변경하지 않고도 더 많은 입력을 절약할 수 있습니다.
for x in src/**/*.foo; do foo $x >../dest/${${x#*/}%.*}.changed.foo; done
for x in src/**/*.foo; do foo $x >../dest/${x#*/}:r.changed.foo; done
for x (src/**/*.foo) foo $x >../dest/${x#*/}:r.changed.foo
이 작업을 자주 수행하는 경우 예를 들어 GNUmakefile에서 빌드 규칙을 정의해야 합니다(탭을 사용하여 8개의 공백을 사용함).
source_files = $(shell find src -name '*.foo')
destination_files = $(patsubst src/,dest/,$($(source_files)%.foo=.changed.foo))
default: all-foo
all-foo: $(destination_files)
dest/%.changed.foo: src/%.foo
foo $< >$@
답변2
파일 이름에 개행 문자가 포함되어 있지 않다고 가정합니다.
find src -name '*.foo' -type f | \
while IFS= read -r sf; do
df=dest/${sf##./src/} && \
mkdir -p "$(dirname "$df")" && \
foo "$sf" >"${df%%.foo}.changed.foo"
done
답변3
소스 파일 트리가 없다고 가정하면(예: no src/dir1/a.foo
; 모두 src
디렉토리에 직접 있음) find
래퍼가 필요하지 않으며 셸에서 직접 실행할 수 있습니다.
for x in src/*.foo
do
dest="${x/src/dest}"
foo "$x" > "${dest/%.foo/.changed.foo}"
done
여기서 복잡한 점은 파일 이름을 변경하고 싶은데 이것이 foo
.
foo
현재 디렉터리에서 실행할 필요가 없다면 조금 더 쉽게 만들 수 있습니다.
cd src
for x in *.foo
do
foo "$x" > "../dest/${x/%.foo/.changed.foo}"
done
확장자를 변경하고 싶지 않다면 이것이 가장 간단한 루프입니다.
cd src
for x in *.foo
do
foo "$x" > "../dest/$x"
done
문자를 전략적으로 사용하면 이러한 모든 루프를 한 줄로 바꿀 수 있습니다 ;
. 예를 들어 첫 번째 루프는 다음과 같습니다.
for x in src/*.foo; do dest="${x/src/dest}" ; foo "$x" > "${dest/%.foo/.changed.foo}" ; done