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
文字を戦略的に使用すると、これらすべてのループを1行に置き換えることができます;
。たとえば、最初のループは次のようになります。
for x in src/*.foo; do dest="${x/src/dest}" ; foo "$x" > "${dest/%.foo/.changed.foo}" ; done