誰かが次のことを行うためのコードを提供してくれませんか?ファイルのディレクトリがあり、そのすべてをプログラムで実行する必要があるとします。プログラムは結果を標準出力に出力します。ディレクトリに移動し、各ファイルでコマンドを実行し、出力を1つの大きな出力ファイルに連結するスクリプトが必要です。
たとえば、1つのファイルに対してコマンドを実行するには:
$ cmd [option] [filename] > results.out
誰かが次のことを行うためのコードを提供してくれませんか?ファイルのディレクトリがあり、そのすべてをプログラムで実行する必要があるとします。プログラムは結果を標準出力に出力します。ディレクトリに移動し、各ファイルでコマンドを実行し、出力を1つの大きな出力ファイルに連結するスクリプトが必要です。
たとえば、1つのファイルに対してコマンドを実行するには:
$ cmd [option] [filename] > results.out
回答:
次のbashコードは$ fileをコマンドに渡し、$ fileは/ dir内のすべてのファイルを表します
for file in /dir/*
do
cmd [option] "$file" >> results.out
done
例
el@defiant ~/foo $ touch foo.txt bar.txt baz.txt
el@defiant ~/foo $ for i in *.txt; do echo "hello $i"; done
hello bar.txt
hello baz.txt
hello foo.txt
/dir/
でも、ループは「*」の値で1回実行されますが$file
、これは望ましくない場合があります。これを回避するには、ループの期間中nullglobを有効にします。ループの前にこの行を追加し、ループのshopt -s nullglob
後にこの行を追加しますshopt -u nullglob #revert nullglob back to it's normal default state
。
done >results.out
です(おそらく、ここで想定しているように、追加する代わりに上書きすることができます)。
これはどう:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
-maxdepth 1
引数は、findが再帰的にサブディレクトリに降りることを防ぎます。(そのようなネストされたディレクトリを処理させたい場合は、これを省略できます。)-type -f
プレーンファイルのみが処理されることを指定します。-exec cmd option {}
見つかったファイルごとにcmd
指定さoption
れたファイル名で置き換えて実行するように指示します{}
\;
コマンドの終わりを示します。cmd
実行からの出力はにリダイレクトされます
results.out
ただし、ファイルが処理される順序を気にする場合は、ループを作成した方がよい場合があります。私find
はファイルをiノードの順序で処理すると思います(ただし、それについては間違っている可能性があります)。
stat
やなどの他のコマンドを使用して並べ替えを行うこともできますsort
。これはもちろん、並べ替えの基準に依存します。
-exec
オプションの後にそれらをどのようにリンクしますか?それらを一重引用符で囲む必要がありますか?
find
常に最良のオプションです。オプションを使用してファイル名パターンでフィルタリング-name
でき、単一のコマンドで実行できます。
-exec
オプション:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
受け入れられた/高い投票の答えは素晴らしいですが、いくつかの重要な詳細が欠けています。この投稿では、シェルのパス名の展開(glob)が失敗した場合、ファイル名に改行/ダッシュ記号が埋め込まれていて、結果をファイル。
実行しているときに使用したシェルグロブ拡張*
が存在しない場合は展開が失敗する可能性がある何のディレクトリに存在するファイルと非拡大グロブ文字列は、望ましくない結果を持っている可能性があり、実行するコマンドに渡されます。bash
シェルはこの使用のために拡張されたシェルのオプションを提供しますnullglob
。したがって、ループは基本的にファイルを含むディレクトリ内で次のようになります
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
これにより、式./*
がファイルを返さない場合(ディレクトリが空の場合)にforループを安全に終了できます。
またはPOSIXに準拠した方法で(nullglob
あるbash
特定の)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
これにより、式が1回失敗したときにループ内に移動し、[ -f "$file" ]
展開されていない文字列./*
がそのディレクトリ内の有効なファイル名であるかどうかを条件チェックします。したがって、この条件が満たされない場合continue
は、for
ループを再開して、その後は実行されないようにします。
また--
、ファイル名引数を渡す直前の使用法にも注意してください。前述のように、シェルのファイル名にはファイル名のどこにでもダッシュを含めることができるため、これが必要です。一部のシェルコマンドはそれを解釈し、名前が適切に引用符で囲まれていない場合はコマンドオプションとして扱い、フラグが指定されているかどうかを考慮してコマンドを実行します。
--
信号コマンドがコマンドフラグとしてではなくファイル名のみ、このポイントを超えて任意の文字列を解析するべきではない手段、その場合のコマンドラインオプションの終わり。
ファイル名を二重引用符で囲むと、名前にグロブ文字または空白が含まれる場合が正しく解決されます。ただし、* nixファイル名には改行を含めることもできます。したがって、有効なファイル名の一部にできない唯一の文字、つまりnullバイト(\0
)でファイル名を区切ります。以来bash
、内部で使用してC
ヌルバイトが文字列の終わりを示すために使用されているスタイルの文字列を、それがこのために右の候補です。
したがってprintf
、シェルのオプションを使用して、このNULLバイトでファイルを区切る-d
オプションを使用してread
コマンドは、以下のようにします
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
nullglob
そしてprintf
周りにラップさ(..)
を避けるためにため、彼らは基本的に、サブシェル(子シェル)で実行されていることを意味するnullglob
コマンドが終了後、親シェルに反映するオプションを選択します。コマンドの-d ''
オプションはPOSIXに準拠していないため、これを実行するにはシェルが必要です。使用するread
bash
find
コマンドすると、これは次のように行うことができます
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
以下のためにfind
サポートしない実装-print0
(GNUとFreeBSDの実装以外)、これを使用してエミュレートすることができますprintf
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
もう1つの重要な修正は、リダイレクトをforループの外に移動して、ファイルI / Oの数を減らすことです。ループ内で使用する場合、シェルはforループの反復ごとに2回システムコールを実行する必要があります。1回はファイルを開くため、もう1回はファイルに関連するファイル記述子を閉じるためです。これは、大きな反復を実行するためのパフォーマンスのボトルネックになります。推奨される提案は、ループの外に移動することです。
この修正で上記のコードを拡張すると、
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
これは基本的に、stdoutへのファイル入力の反復ごとにコマンドの内容を配置し、ループが終了したら、stdoutの内容を書き込んで保存するためにターゲットファイルを1回開きます。find
同じものの同等のバージョンは
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
仕事を成し遂げるための1つの迅速で汚い方法は次のとおりです。
find directory/ | xargs Command
たとえば、現在のディレクトリのすべてのファイルの行数を見つけるには、次のようにします。
find . | xargs wc -l
~/.local/share/steam
た。Ranスチーム。ユーザーが所有するシステム上のすべてを削除した」のようなもので終わる。バグレポート。
私はすべての.mdファイルを1つのディレクトリから別のディレクトリにコピーする必要があったので、ここで私がやったことです。
for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
これはかなり読みにくいので、分解してみましょう。
最初に、ファイルのあるディレクトリにcdします。
for i in **/*.md;
パターン内の各ファイル
mkdir -p ../docs/"$i"
ファイルを含むフォルダーの外のdocsフォルダーにそのディレクトリを作成します。これにより、そのファイルと同じ名前で追加のフォルダーが作成されます。
rm -r ../docs/"$i"
の結果として作成された余分なフォルダを削除します mkdir -p
cp "$i" "../docs/$i"
実際のファイルをコピーする
echo "$i -> ../docs/$i"
あなたがしたことをエコー
; done
末永く幸せに過ごす
**
仕事に、globstar
シェルオプションを設定する必要がありますshopt -s globstar
@ジム・ルイスのアプローチに基づく:
ここでは、find
ファイルを使用し、変更日でファイルを並べ替える簡単なソリューションを示します。
$ find directory/ -maxdepth 1 -type f -print0 | \
xargs -r0 stat -c "%y %n" | \
sort | cut -d' ' -f4- | \
xargs -d "\n" -I{} cmd -op1 {}
並べ替えについては、以下を参照してください。
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time
-print0
for find
と-0
for について、xargs
ホワイトスペース(改行を含む)の代わりにnull文字を使用することについての詳細を読みたい場合があります。
-print0
することは役立ちますが、パイプライン全体sort
はこのようなものを使用する必要があり、そうではありません
私はそれがジム・ルイスの答えでうまく機能することを発見しました。
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
$ find . -maxdepth 1 -type f -name '*.sh' -exec {} \; > results.out
ソート順で実行したい場合は、次のように変更します。
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -maxdepth 2 -type f -name '*.sh' | sort | bash > results.out
例として、これは次の順序で実行されます。
bash: 1: ./assets/main.sh
bash: 2: ./builder/clean.sh
bash: 3: ./builder/concept/compose.sh
bash: 4: ./builder/concept/market.sh
bash: 5: ./builder/concept/services.sh
bash: 6: ./builder/curl.sh
bash: 7: ./builder/identity.sh
bash: 8: ./concept/compose.sh
bash: 9: ./concept/market.sh
bash: 10: ./concept/services.sh
bash: 11: ./product/compose.sh
bash: 12: ./product/market.sh
bash: 13: ./product/services.sh
bash: 14: ./xferlog.sh
特定の条件で無制限の深さで実行したい場合は、これを使用できます:
export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -type f -name '*.sh' | sort | bash > results.out
次に、次のように子ディレクトリの各ファイルの上に配置します。
#!/bin/bash
[[ "$(dirname `pwd`)" == $DIR ]] && echo "Executing `realpath $0`.." || return
親ファイルの本文のどこかに:
if <a condition is matched>
then
#execute child files
export DIR=`pwd`
fi
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out