Linuxでディレクトリをループする方法は?


168

Linuxのbashでスクリプトを作成していて、指定されたディレクトリ内のすべてのサブディレクトリ名を調べる必要があります。これらのディレクトリをループする(および通常のファイルをスキップする)にはどうすればよいですか?

例:
指定されたディレクトリ/tmp/
には、次のサブディレクトリがあります。/tmp/A, /tmp/B, /tmp/C

A、B、Cを取得したい。


回答:


129
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

簡単な説明:

  • find ファイルを見つける(明らかに)

  • .後に、現在のディレクトリ、あるcdある/tmp(私見はこれが持つよりも柔軟性がある/tmp中で直接findコマンドを実行します。あなたは、唯一の場所を持っているcdあなたはより多くのアクションがこのフォルダに場所を取るしたい場合は、変更に、)

  • -maxdepth 1-mindepth 1ことを確認してfind、現在のディレクトリにあるルックスとは含まれていない.結果に自分自身を

  • -type d ディレクトリのみを探す

  • -printf '%f\n ヒットごとに、見つかったフォルダの名前(および改行)のみを出力します。

エボラ!


ちなみに、すべての回答で隠しフォルダー(つまり、ドットで始まるフォルダー)も検索されます。これが不要な場合は、printfまたはexecオプションの前に `-regex '\ ./ [^ \。]。*'`を追加します。
Boldewyn、2010年

1
役立つ—ヒットごとに1つのコマンドのみを実行する必要がある場合;-) —実行するコマンドがいくつかあるだけです:
Martin

問題ありません:このソリューションを採用しwhile..doneください:transnum.blogspot.de/2008/11/…ループ内では、クレイジーになることができます。
Boldewyn 2014年

1
これは、いくつかのユースケースにとって非常に優れた方法です。find-execオプションを使用すると、ファイル/ディレクトリごとに任意のコマンドを実行できます。
jtpereyda 2017

451

これまでのすべての回答はを使用findしているため、ここではシェルのみを使用したものを示します。あなたのケースでは外部ツールは必要ありません:

for dir in /tmp/*/     # list directories in the form "/tmp/dirname/"
do
    dir=${dir%*/}      # remove the trailing "/"
    echo ${dir##*/}    # print everything after the final "/"
done

18
+ find
1-

19
そうfor dir in */; do echo $dir; done、現在のディレクトリ内のディレクトリです。
Ehtesh Choudhury 2013

41
それが何dir=${dir%*/}をしecho ${dir##*/}ているかの説明を含めることができればいいのですが。
ジェレミーS.

11
これは、変数dirの最後にバックスラッシュが含まれるためです。クリーンな名前にするために削除しています。%は最後の/を削除します。##は最初の/を削除します。これらは、部分文字列を処理する演算子です。
sfratini、2015年

8
一致しない場合、ループはでトリガーされ/tmp/*/ます。ディレクトリが実際に存在するかどうかを確認するチェックを含めることをお勧めします。
Jrs42

41

隠しディレクトリ(ドットで始まる)を含むすべてのディレクトリをループできます。

for file in */ .*/ ; do echo "$file is a directory"; done

注:リストの使用は*/ .*/、フォルダーに少なくとも1つの隠しディレクトリが存在する場合にのみzshで機能します。bashで、それも表示されます.と、..


bashが隠しディレクトリを含めるもう1つの方法は、次のようにすることです。

shopt -s dotglob;
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

各ソリューションで末尾のディレクトリ名(問題のA、B、C)のみを出力するには、ループ内でこれを使用します。

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"

例(これはスペースを含むディレクトリでも機能します):

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done

16

スペースを含むディレクトリで動作します

ソルピガルに触発された

while IFS= read -d $'\0' -r file ; do 
    echo $file; ls $file ; 
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)

元の投稿(スペースでは機能しません)

Boldewynに触発された:findコマンドを使用したループの例。

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done


6

私が最もよく使うテクニックはfind | xargsです。たとえば、このディレクトリとそのすべてのサブディレクトリにあるすべてのファイルを誰でも読み取り可能にする場合は、次のようにします。

find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx

-print0オプションは、スペースの代わりにNULL文字で終了します。-0オプションは、その入力と同じように分割します。したがって、これはスペースを含むファイルで使用する組み合わせです。

この一連のコマンドfindは、chmodコマンドの最後に貼り付けてすべての行出力を取得するように描くことができます。

コマンドを最後ではなく途中で引数として実行する場合は、少し工夫する必要があります。たとえば、すべてのサブディレクトリに移動してコマンドを実行する必要がありましたlatemk -c。だから私は(ウィキペディアから)使用しました:

find . -type d -depth 1 -print0 | \
    xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord

これにはの効果がfor dir $(subdirs); do stuff; doneありますが、名前にスペースが含まれるディレクトリでは安全です。また、への個別の呼び出しstuffは同じシェルで行われるため、私のコマンドではで現在のディレクトリに戻る必要がありpopdます。


3

構築できる最小限のbashループ(ベースのghostdog74回答)

for dir in directory/*                                                     
do                                                                                 
  echo ${dir}                                                                  
done

ディレクトリごとにファイル全体を圧縮する

for dir in directory/*
do
  zip -r ${dir##*/} ${dir}
done                                               

directoryサブディレクトリだけでなく、のすべてのファイルが一覧表示されます。
dexteritas

2

find . -type d -maxdepth 1


2
この答えは良いですが、フルパスを受け取りますが、ディレクトリの名前だけが必要です。
Erik Sapir、2010年

2

forループで複数のコマンドを実行する場合は、findwith mapfile(bash> = 4)の結果を変数として保存し、で配列を調べることができます${dirlist[@]}。スペースを含むディレクトリでも機能します。

findコマンドが基づいている答え Boldewynによります。findコマンドの詳細については、こちらをご覧ください。

IFS=""
mapfile -t dirlist < <( find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n' )
for dir in ${dirlist[@]}; do
    echo ">${dir}<"
    # more commands can go here ...
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.