
ls
ディレクトリ名のリストを取得して、各ディレクトリ名をループして何かを実行するためのテンプレート シェル スクリプトを持っている人はいますか?
ls -1d */
ディレクトリ名のリストを取得する予定です。
答え1
@shawn-j-goff や他のユーザーの提案に従って、glob が使用される場所では ls を使用しないように編集しました。
ループを使用するだけですfor..do..done
:
for f in *; do
echo "File -> $f"
done
を、またはリスト (ファイル、ディレクトリ、その他何でも) を返すその他の glob、リストを生成するコマンド (例: )*
に置き換えたり、実際にリストに置き換えたりすることができます。*.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
答え2
の出力を使用して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 つあります。1 つ目は です{}
。この引数は、 の前の部分が生成したファイル名に置き換えられますfind
。2 つ目は で;
、find
これはプログラムに渡す引数のリストの終わりであることを示します。 には、実行されたプログラムfind
用とそうでない引数をさらに続けることができるため、これが必要ですfind
。 の理由は、\
シェルも を;
特別扱いするためです。 はコマンドの終わりを表すので、シェルがそれを自分自身で消費するのではなく、 の引数として渡すようにエスケープする必要がありますfind
。シェルが を特別扱いしないようにする別の方法は、 を引用符で囲むことです。は、この目的に';'
は と同じように機能します。\;
答え3
スペースを含むファイルの場合は、次のように変数を引用符で囲む必要があります。
for i in $(ls); do echo "$i"; done;
または、入力フィールドセパレーター (IFS) 環境変数を変更することもできます。
(IFS=$'\n';for i in $(ls); do echo $i; done) # subshell to restore IFS
最後に、何をしているかに応じて、ls さえ必要ない場合もあります。
for i in *; do echo "$i"; done;
答え4
CoverosGene の回答に追加して、ディレクトリ名だけを一覧表示する方法は次のとおりです。
for f in */; do
echo "Directory -> $f"
done