ディレクトリ名のリストのためにls
を使って何かをし、それぞれをループして何かをするためのテンプレートシェルスクリプトがありますか?
ディレクトリ名のリストを取得するためにls -1d */
をやるつもりです。
@ shawn-j-goffや他の人が示唆しているように、globがするところでは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
ls
の出力を使ってファイル名を取得するのは悪い考えです 。それは誤動作やさらには危険なスクリプトを引き起こす可能性があります。これは、ファイル名に/
とnull
文字以外の任意の文字を含めることができ、ls
がこれらの文字のどちらも区切り文字として使用しないため、ファイル名にスペースまたは改行がある場合、予期しない結果になります。
ファイルを反復処理する方法は2つあります。ここでは、ファイル名を使用して何かを実行する方法を示すために、単にecho
を使用しました。しかし、あなたは何でも使うことができます。
1つはシェルのネイティブグロビング機能を使うことです。
for dir in */; do
echo "$dir"
done
シェルは*/
をfor
ループが読み込む別々の引数に展開します。ファイル名にスペース、改行、その他の奇妙な文字が含まれていても、for
はそれぞれの完全な名前をアトミックな単位として認識します。リストを解析するわけではありません。
サブディレクトリに再帰的に入りたいのであれば、シェルに拡張グロブ機能(bash
のglobstar
など)がない限り、これはできません。シェルにこれらの機能がない場合、またはスクリプトを確実に機能させたい場合さまざまなシステムでは、次のオプションはfind
を使うことです。
find . -type d -exec echo '{}' \;
ここで、find
コマンドはecho
を呼び出し、ファイル名の引数を渡します。見つけたファイルごとにこれを1回行います。前の例と同様に、ファイル名のリストの解析はありません。代わりに、ファイル名は引数として完全に送信されます。
-exec
引数の構文は少し変わって見えます。 find
は-exec
の後の最初の引数を取り、それを実行するプログラムとして扱い、それ以降のすべての引数はそのプログラムに渡す引数として取ります。 -exec
が見る必要がある2つの特別な引数があります。最初のものは{}
です。この引数は、find
の前の部分が生成するファイル名に置き換えられます。 2つ目は;
で、これはfind
にこれがプログラムに渡す引数のリストの最後であることを知らせます。 find
はこれを必要とします。これはfind
を対象とし、execされたプログラムを対象としないより多くの引数を続けることができるからです。 \
の理由は、シェルが;
を特別に扱うからです。それはコマンドの終わりを表します。したがって、シェルがそれをfind
への引数として渡すのではなく、それをエスケープする必要があります。シェルが特別に扱わないようにするもう1つの方法は、引用符で囲むことです。';'
は、この目的のために\;
と同じように機能します。
スペースが含まれているファイルの場合は、必ず次のように変数を引用符で囲む必要があります。
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;
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
CoverosGeneの答えに加えて、ディレクトリ名だけをリストする方法があります。
for f in */; do
echo "Directory -> $f"
done
IFSを改行に設定してからls
の出力を配列にキャプチャしませんか? IFSを改行に設定すると、ファイル名におかしな文字が含まれる問題を解決するはずです。 ls
を使用すると、ソート機能が組み込まれているので、Niceにすることができます。
(テストでは、IFSを\n
に設定するのに問題がありましたが、改行のバックスペースに設定すると、ここで他の場所で示唆されているように動作します)
例えば。 ($1
に渡される必要なls
検索パターンを仮定します):
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
です。