いくつかのディレクトリといくつかのファイルを含むフォルダがあります(一部はドットで始まり、非表示になっています)。
for d in *; do
echo $d
done
すべてのファイルをループしますが、ディレクトリのみをループしたいと思います。それ、どうやったら出来るの?
ディレクトリだけでなく特定のファイルを選択する必要がある場合は、find
を使用してwhile read
に渡します。
shopt -s dotglob
find * -Prune -type d | while IFS= read -r d; do
echo "$d"
done
隠しディレクトリを除外するには、shopt -u dotglob
を使用します(またはzshではsetopt dotglob
/unsetopt dotglob
)。
IFS=
は、$IFS
のいずれかを含むファイル名の分割を回避します。例:'a b'
find
オプションの詳細については、以下の AsymLabs回答 を参照してください
編集:
whileループ内から終了値を作成する必要がある場合は、次のトリックで余分なサブシェルを回避できます。
while IFS= read -r d; do
if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -Prune -type d)
末尾にスラッシュを指定して、ディレクトリのみに一致させることができます。
for d in */ ; do
echo "$d"
done
チョロバのソリューションは洗練されていますが、現在のディレクトリ内にディレクトリがない場合、予期しない動作を引き起こす可能性があることに注意してください。この状態では、for
ループをスキップするのではなく、bashはd
が*/
と等しい場合にループを1回だけ実行します。
#!/usr/bin/env bash
for d in */; do
# Will print */ if no directories are available
echo $d
done
このケースから保護するために、以下を使用することをお勧めします。
#!/usr/bin/env bash
for f in *; do
if [ -d ${f} ]; then
# Will not run if no directories are available
echo $f
fi
done
このコードは現在のディレクトリ内のすべてのファイルをループし、f
がディレクトリかどうかを確認し、条件がtrueを返す場合はf
をエコーします。 f
が*/
と等しい場合、echo $f
は実行されません。
そのために純粋なbashを使用できますが、findを使用することをお勧めします。
find . -maxdepth 1 -type d -exec echo {} \;
(さらに、隠しディレクトリが含まれます)
これは、ルートディレクトリを除く、現在の作業ディレクトリ内の可視ディレクトリと非表示ディレクトリの両方を見つけるために行われます。
ディレクトリをループするだけです:
find -path './*' -Prune -type d
結果にシンボリックリンクを含めるには:
find -L -path './*' -Prune -type d
各ディレクトリに対して何かを行うには(シンボリックリンクを除く):
find -path './*' -Prune -type d -print0 | xargs -0 <cmds>
隠しディレクトリを除外するには:
find -path './[^.]*' -Prune -type d
戻り値に対して複数のコマンドを実行するには(非常に不自然な例):
find -path './[^.]*' -Prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"
「sh -c」の代わりに「bash -c」なども使用できます。
これには、リスト内の各ディレクトリの完全なパスが含まれます。
for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done
隠しディレクトリ(ドットで始まる)を含むすべてのディレクトリを1行でループし、次のように複数のコマンドをループできます。
for file in */ .*/ ; do echo "$file is a directory"; done
シンボリックリンクを除外したい場合:
for file in *; do
if [[ -d "$file" && ! -L "$file" ]]; then
echo "$file is a directory";
fi;
done
注:リスト*/ .*/
を使用するとbashで機能しますが、フォルダー.
および..
も表示されますが、zshではこれらは表示されませんが、存在しない場合はエラーがスローされます。フォルダ内の隠しファイル
隠しディレクトリを含め、.. /を除外するよりクリーンなバージョンは、dotglobオプションを使用します。
shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done
(またはsetopt dotglob
in zsh)
あなたはdotglobを解除することができます
shopt -u dotglob
find
を-exec
とともに使用して、ディレクトリをループし、execオプションでfunctionを呼び出します。
dosomething () {
echo "doing something with $1"
}
export -f dosomething
find -path './*' -Prune -type d -exec bash -c 'dosomething "$0"' {} \;
shopt -s dotglob
またはshopt -u dotglob
を使用して、隠しディレクトリを含めたり除外したりします
ls -d */ | while read d
do
echo $d
done
これは、指定されたパス内のサブディレクトリの数とともにすべてのディレクトリを一覧表示します。
for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done