web-dev-qa-db-ja.com

bashでディレクトリのみをループするにはどうすればよいですか?

いくつかのディレクトリといくつかのファイルを含むフォルダがあります(一部はドットで始まり、非表示になっています)。

for d in *; do
 echo $d
done

すべてのファイルをループしますが、ディレクトリのみをループしたいと思います。それ、どうやったら出来るの?

287
rubo77

ディレクトリだけでなく特定のファイルを選択する必要がある場合は、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)
24
rubo77

末尾にスラッシュを指定して、ディレクトリのみに一致させることができます。

for d in */ ; do
    echo "$d"
done
374
choroba

-dでテストできます:

for f in *; do
    if [ -d "$f" ]; then
        # $f is a directory
    fi
done

これは ファイルテスト演算子 の1つです。

85
goldilocks

チョロバのソリューションは洗練されていますが、現在のディレクトリ内にディレクトリがない場合、予期しない動作を引き起こす可能性があることに注意してください。この状態では、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は実行されません。

34
emagdne

そのために純粋なbashを使用できますが、findを使用することをお勧めします。

find . -maxdepth 1 -type d -exec echo {} \;

(さらに、隠しディレクトリが含まれます)

12
rush

これは、ルートディレクトリを除く、現在の作業ディレクトリ内の可視ディレクトリと非表示ディレクトリの両方を見つけるために行われます。

ディレクトリをループするだけです:

 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」なども使用できます。

7
AsymLabs

これには、リスト内の各ディレクトリの完全なパスが含まれます。

for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done
3
user26053

隠しディレクトリ(ドットで始まる)を含むすべてのディレクトリを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
3
rubo77

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を使用して、隠しディレクトリを含めたり除外したりします

0
rubo77
ls -d */ | while read d
do
        echo $d
done
0
dcat

これは、指定されたパス内のサブディレクトリの数とともにすべてのディレクトリを一覧表示します。

for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done
0
pabloa98