次の名前のファイルを含むフォルダがあるとします。
file1.txt
file2.txt
file2.txt
など。次のようにそれぞれに対してコマンドを実行したいと思います。
mycommand file1.txt -o file1-processed.txt
mycommand file2.txt -o file2-processed.txt
mycommand file3.txt -o file3-processed.txt
など。
-processed
このサイトにはいくつかの同様の質問があります。違いは、拡張子の前のファイル名の途中にテストを挿入したいことです。
find
作業のためのツールになりそうです。旗なしでも-o
できます
find *.txt -exec mycommand "{}" ";"
ただし、{}
構文はなどのように完全なファイル名を提供するため、ファイル名と拡張子の間に ""を追加することfile1.txt
はできません。-processed
単純なbashループを使用するとfor
同様の問題があります。
これを行う簡単な方法はありますかfind
?
答え1
処理するすべてのファイルが同じフォルダにある場合は必要ではなく、デフォルトのシェルfind
ワイルドカードを使用できます。
for foo in *.txt ; do
mycommand "${foo}" -o "${foo%.txt}-processed.txt"
done
シェルイディオムは、パターン${foo%bar}
(この場合は拡張子)に一致する最小のサフィックス文字列を値から削除するため、必要なサフィックスに置き換えることができます。bar
foo
.txt
答え2
さまざまなシステムで実行されるスクリプトを作成し、移植性を念頭に置いている場合は、繰り返して起動するのとfor
同じ${var%sfx}
くらい良いことはありません。ユーザー 1404316答え。
しかし、自分のシステムで同様の作業を実行する便利な方法を探している場合は、心からお勧めします。GNUパラレル、これは基本的にxargs
ステロイドです。特定のタスクの解決策は次のとおりです。
parallel mycommand {} -o {.}-processed.txt ::: *.txt
次に、文字列リスト:::
(シェルが*.txt
一致するファイル名のリストに展開されます)を取得し、各文字列に対して実行して、mycommand {} -o {.}-processed.txt
入力文字列{}
(たとえばxargs
)と{.}
拡張子のないファイル名を変更します。
stdin
(これでこれを行うことができます。パラメータfind
-way)、またはとペアになりますが、拡張グローブ以外はlocate
ほとんど必要ありません。zsh
見てGNUパラレルチュートリアルそれができることを学びましょう。バッチ変換、サブディレクトリへのアーカイブ抽出などに常に使用します。
答え3
これは適応するユーザー1404316の回答アクションfind
:
find . -type f -name '*.txt' \
-exec sh -c 'for file do mycommand "$file" -o "${file%.txt}-processed.txt"; done' sh {} +
(すべての内容を1行に入力できます。省略してください。\
読みやすくするために2行に分けてください。)
読みやすくするために書式設定する別の方法で埋め込まれたシェルスクリプトをより明確にします。
find . -type f -name '*.txt' -exec sh -c '
for file
do
mycommand "$file" -o "${file%.txt}-processed.txt";
done
' sh {} +
デフォルトでは、名前のないシェルスクリプトを生成します。
for file
do
mycommand "$file" -o "${file%.txt}-processed.txt"
done
(二重引用符の間の文字列、拡張)すべてのファイル名を引数として'…'
command() としてシェルに渡します。 (一般的に引用は不要で、中括弧を使用しません。)sh -c
.txt
{}
"$file"
答え4
再帰およびより複雑な文字列置換が必要な場合find
、sed
および組み合わせが機能する可能性があります。xargs
find . -iname '*.txt' -printf "%p\0-o\0%p\0" | sed -z '3~3s/\.txt$/-processed&/' | xargs -0 -n 3 echo mycommand
例:
$ find
.
./bar baz.txt
./foo.txt
$ find . -iname '*.txt' -printf "%p\0-o\0%p\0" | sed -z '3~3s/\.txt$/-processed&/' | xargs -0 -n 3 echo mycommand
mycommand ./bar baz.txt -o ./bar baz-processed.txt
mycommand ./foo.txt -o ./foo-processed.txt
このコマンドは-printf "%p\0-o\0%p\0"
ファイルパスを-o
ASCII NUL文字で区切って2回印刷し、3行目の末尾の行に1つを挿入しますsed
。次に、一度に3つの引数(ファイル名と編集されたファイル名)を使用してコマンドを実行します。-processed
.txt
xargs
-o