ls
ディレクトリ名のリストに対して何かを実行し、それぞれをループして何かを実行するためのテンプレートシェルスクリプトはありますか?
ls -1d */
ディレクトリ名のリストを取得する予定です。
ls
ディレクトリ名のリストに対して何かを実行し、それぞれをループして何かを実行するためのテンプレートシェルスクリプトはありますか?
ls -1d */
ディレクトリ名のリストを取得する予定です。
回答:
@ shawn-j-goffや他の人が示唆したように、グロブが行う場所でlsを使用しないように編集されました。
for..do..done
ループを使用するだけです:
for f in *; do
echo "File -> $f"
done
あなたは置き換えることができ*
て*.txt
たり(ファイル、ディレクトリ、またはそのことについては何の)リストを返し、他のグロブ、リストを生成するコマンド、例えば、$(cat filelist.txt)
あるいは実際のリストに置き換えます。
do
ループ内では、ループ変数をドル記号のプレフィックスで参照するだけです($f
上記の例では)。あなたはecho
それをするか、あなたが望む他の何かをします。
たとえば.xml
、現在のディレクトリ内のすべてのファイルの名前を次のように変更します.txt
。
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
さらに良いことに、Bashを使用している場合は、サブシェルを作成するのではなく、Bashパラメーター展開を使用できます。
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
ループの非常に一般的な誤用と、の出力を解析しようとする典型的な落とし穴を示していますls
。@ DanielA.White、あなたが言ったようにディレクトリで行動しているので、役に立たなかった(または潜在的に誤解を招く可能性がある)場合、この答えを受け入れないことを検討するかもしれません。Shawn J. Goffの答えは、あなたの問題に対してより堅牢で実用的なソリューションを提供するはずです。
ls
出力を、あなたが出力読むべきではないfor
ループを、あなたが使用する必要があります$()
``の代わりに及びその他の引用符を使用し™。@CoverosGeneの意味は確かだと思いますが、これはひどいです。
ls
はls -1 | while read line; do stuff; done
です。少なくとも空白の場合は壊れません。
mv -v
、あなたは必要ありませんecho "moved $x -> $t"
の出力を使用してls
ファイル名を取得することはお勧めできません。誤動作や危険なスクリプトにさえつながる可能性があります。ファイル名は除く任意の文字含めることができるからである/
とnull
文字を、およびls
区切り文字としてこれらの文字のいずれかを使用していないので、ファイル名が空白や改行を持っている場合、あなたがなり、予期しない結果が得られます。
ファイルを反復処理する2つの非常に良い方法があります。ここでは、単にecho
ファイル名を使って何かを行うことを示すために使用しています。ただし、何でも使用できます。
1つ目は、シェルのネイティブグロビング機能を使用することです。
for dir in */; do
echo "$dir"
done
シェルは*/
、for
ループが読み取る個別の引数に展開されます。ファイル名にスペース、改行、またはその他の奇妙な文字が含まれている場合でも、for
各完全な名前はアトミック単位として表示されます。リストを解析することはありません。
再帰的にサブディレクトリに移動する場合、シェルに拡張グロブ機能(bash
's など)がない限り、これは実行されませんglobstar
。シェルにこれらの機能がない場合、またはスクリプトが機能することを確認する場合さまざまなシステムで、次のオプションはを使用することfind
です。
find . -type d -exec echo '{}' \;
ここで、find
コマンドはecho
ファイル名の引数を呼び出して渡します。これは、見つかったファイルごとに1回実行します。前の例と同様に、ファイル名のリストの解析はありません。代わりに、fileneameが引数として完全に送信されます。
-exec
引数の構文は少しおかしく見えます。find
後に最初の引数を取り、-exec
それを実行するプログラムとして扱い、それ以降のすべての引数は、そのプログラムに渡す引数として受け取ります。-exec
確認する必要がある2つの特別な引数があります。最初のものは{}
; この引数は、の前の部分がfind
生成するファイル名に置き換えられます。2つ目はで;
、これfind
はプログラムに渡す引数のリストの最後であることを知らせます。exec'dプログラムを対象としたものとfind
対象外の引数をさらに続けることができるため、これが必要ですfind
。その理由\
は、シェルも処理することです;
特に-コマンドの終わりを表すので、シェルがそれを引数として与えるためにそれをエスケープする必要がありfind
ます。シェルを特別に扱わないようにする別の方法は、引用符で囲むことです:この目的';'
と同様に機能し\;
ます。
find
。実行できる魔法があり、認識されている制限さえも-exec
回避することができます。この-print0
オプションは、との使用にも役立ちますxargs
。
スペースを含むファイルの場合、次のように変数を引用符で囲む必要があります。
for i in $(ls); do echo "$i"; done;
または、入力フィールド区切り文字(IFS)環境変数を変更できます。
IFS=$'\n';for file in $(ls); do echo $i; done
最後に、何をしているのかにもよりますが、lsさえ必要ないかもしれません。
for i in *; do echo "$i"; done;
\n
は不十分です。の出力の解析を推奨することは決して良い考えではありませんls
。
GNU Parallel http://www.gnu.org/software/parallel/がインストールされている場合、これを行うことができます。
ls | parallel echo {} is in this dir
すべての.txtの名前を.xmlに変更するには:
ls *.txt | parallel mv {} {.}.xml
詳細については、GNU Parallelの紹介ビデオをご覧ください:http : //www.youtube.com/watch?v=OpaiGYxkSuQ
IFSを改行に設定してからls
、配列の出力をキャプチャしてみませんか?IFSを改行に設定すると、ファイル名に含まれる変な文字に関する問題が解決するはずです。ls
ソート機能が組み込まれているため、using は便利です。
(テストでは、IFSの設定で問題が発生して\n
いましたが、ここで推奨されているように、改行のバックスペースに設定できます):
例(必要なls
検索パターンが渡されると仮定$1
):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
これは、OS Xで特に便利です。たとえば、作成日(最も古いものから古いもの)でソートされたファイルのリストをキャプチャするには、ls
コマンドはls -t -U -r
です。
\n
は不十分です。唯一の有効な解決策は、パス名の展開、またはでforループを使用しますfind
。
これは私がそれを行う方法ですが、おそらくより効率的な方法があります。
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done