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


250

いくつかのディレクトリといくつかのファイル(ドットで始まる非表示のフォルダ)があるフォルダがあります。

for d in *; do
 echo $d
done

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

回答:


333

ディレクトリのみに一致するように、最後にスラッシュを指定できます。

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

7
ディレクトリへのシンボリックリンクも含まれていることに注意してください。
ステファンシャゼル

1
では、シンボリックリンクをどのように除外しますか?
rubo77

3
@ rubo77:[[ -L $d ]]$ dがシンボリックリンクかどうかをテストできます。
チョロバ

1
@AsymLabsこれは誤りset -Pです。ディレクトリを変更するコマンドにのみ影響します。sprunge.us/TNac
クリスダウン

4
@choroba:[[ -L "$f" ]]この場合、symlinksを除外しません。*/末尾のスラッシュを削除する必要があります[[ -L "${f%/}" ]](末尾のスラッシュを含むリンクのテストを参照
rubo77

78

以下でテストできます-d

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

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


8
ディレクトリへのシンボリックリンクが含まれることに注意してください。
ステファンシャゼル

21
if [[ -d "$f" && ! -L "$f" ]]シンボリックリンクを除外します
rubo77

空のディレクトリで中断します。if [[ "$f" = "*" ]]; then continue; fi
Piskvor

30

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

このコードは、現在のディレクトリ内のすべてのファイルをループし、ディレクトリであるかどうかを確認し、条件がtrueを返す場合にfエコーしfます。fがに等しい場合*/echo $f実行されません。


3
はるかに簡単shopt -s nullglob
チョロバ

21

ディレクトリだけが使用するよりも特定のファイルを選択し、それ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'

その他のオプションについては、AsymLabsの回答を参照してくださいfind


編集:
whileループ内から終了値を作成する必要がある場合は、このトリックによって余分なサブシェルを回避できます。

while IFS= read -r d; do 
    if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)


11

そのために純粋なbashを使用できますが、findを使用する方が適切です。

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

(findには追加で隠しディレクトリが含まれます)


8
ディレクトリへのシンボリックリンクが含まれていないことに注意してください。shopt -s dotglobfor bashを使用して、隠しディレクトリを含めることができます。あなたも含まれます.。また、これ-maxdepthは標準オプション(-pruneis)ではないことに注意してください。
ステファンシャゼル

2
このdotglobオプションは興味深いですがdotglob、の使用にのみ適用されます*find .常に隠しディレクトリ(および現在のディレクトリ)が含まれます
rubo77

6

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

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

 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 d in echo * /」のエコー「* /」にたとえば60,000個のディレクトリが含まれている場合はどうなりますか?
AsymLabs

「Too many files」エラーが表示されますが、解決できます
。debian

1
xargsの例は、9e.gなどのディレクトリ名のサブセットに対してのみ機能します。スペースや改行を含むものは機能しません)。... -print0 | xargs -0 ...正確な名前がわからない場合に使用することをお勧めします。
アントン

1
@ rubo77は、隠しファイル/ディレクトリと複数のコマンドの実行を除外する方法を追加しました-もちろんこれはスクリプトでも実行できます。
AsymLabs

1
私は関数を使用して、各ディレクトリに何かをする方法を、下部に私の答えに例を追加find * | while read file; do ...
rubo77

3

次のコマンドを使用すると、隠しディレクトリ(ドットで始まる)を含むすべてのディレクトリを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 dotglobzshで)

でドットグロブを解除できます

shopt -u dotglob

2

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

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

1
休憩スペースでフォルダを使用して
アレハンドロSazo

0

findwith -execを使用してディレクトリをループし、execオプションで関数を呼び出します。

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

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

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

-1
ls -d */ | while read d
do
        echo $d
done

This is one directory with spaces in the name-ただし、複数として解析されます。
Piskvor

-5
ls -l | grep ^d

または:

ll | grep ^d

エイリアスとして設定できます


1
残念ながら、これは「ディレクトリのみをループしたい」という質問に答えるとは思いません。lsこれは、ディレクトリをリストするこのベースの回答とは少し異なります
ジェフシャラー

1
の出力解析することをお勧めことはありませんlsmywiki.wooledge.org/ParsingLs
codeforester
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.