Jak przeglądać tylko katalogi w bash?


249

Mam folder z niektórymi katalogami i niektórymi plikami (niektóre są ukryte, zaczynając od kropki).

for d in *; do
 echo $d
done

zapętli wszystkie pliki, ale chcę zapętlić tylko katalogi. W jaki sposób mogę to zrobić?

Odpowiedzi:


331

Możesz określić ukośnik na końcu, aby pasował tylko do katalogów:

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

7
Zauważ, że zawiera także dowiązania symboliczne do katalogów.
Stéphane Chazelas

1
jak więc wykluczyłbyś dowiązania symboliczne?
rubo77

3
@ rubo77: Możesz sprawdzić, [[ -L $d ]]czy $ d jest dowiązaniem symbolicznym.
choroba

1
@AsymLabs Niepoprawne, set -Pwpływa tylko na polecenia zmieniające katalog. sprunge.us/TNac
Chris Down

4
@choroba: [[ -L "$f" ]]nie wyklucza dowiązań symbolicznych w tym przypadku za pomocą */, musisz rozebrać ukośnik końcowy za pomocą [[ -L "${f%/}" ]](patrz Test linku z ukośnikiem końcowym )
rubo77


30

Uważaj, że rozwiązanie tej choroby, choć eleganckie, może wywołać nieoczekiwane zachowanie, jeśli w bieżącym katalogu nie ma dostępnych katalogów. W tym stanie, zamiast pomijania forpętli, bash uruchomi pętlę dokładnie raz, gdzie djest równa */:

#!/usr/bin/env bash

for d in */; do
    # Will print */ if no directories are available
    echo $d
done

Zalecam użycie następujących elementów w celu ochrony przed tym przypadkiem:

#!/usr/bin/env bash

for f in *; do
    if [ -d ${f} ]; then
        # Will not run if no directories are available
        echo $f
    fi
done

Ten kod będzie przechodził przez wszystkie pliki w bieżącym katalogu, sprawdza, czy fjest to katalog, a następnie echo, fjeśli warunek zwraca wartość true. Jeśli fjest równe */, echo $fnie zostanie wykonane.


3
O wiele łatwiej shopt -s nullglob.
choroba

21

Jeśli musisz wybrać bardziej szczegółowe pliki, użyj tylko katalogów findi przekaż je do while read:

shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do 
    echo "$d"
done

Służy shopt -u dotglobdo wykluczania ukrytych katalogów (lub setopt dotglob/ unsetopt dotglobw zsh).

IFS=aby uniknąć podziału nazw plików zawierających jeden z $IFS, na przykład:'a b'

zobacz AsymLabs odpowiedzieć poniżej więcej findopcji


edycja:
Jeśli chcesz utworzyć wartość wyjściową z pętli while, możesz obejść dodatkową podpowłokę za pomocą tej sztuczki:

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

2
Znalazłem to rozwiązanie na: stackoverflow.com/a/8489394/1069083
rubo77

11

Możesz użyć do tego czystej bash, ale lepiej użyć find:

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

(znajdź dodatkowo będzie zawierać ukryte katalogi)


8
Zauważ, że nie zawiera dowiązań symbolicznych do katalogów. Możesz użyć shopt -s dotglobdo, bashaby dołączyć ukryte katalogi. Twój będzie również obejmować .. Należy również pamiętać, że -maxdepthnie jest to standardowa opcja ( -prunejest).
Stéphane Chazelas,

2
dotglobOpcja jest interesująca, ale dotglobodnosi się wyłącznie do wykorzystania *. find .zawsze będzie zawierać ukryte katalogi (a także bieżący katalog)
rubo77

6

Odbywa się to w celu znalezienia zarówno widocznych, jak i ukrytych katalogów w bieżącym katalogu roboczym, z wyłączeniem katalogu głównego:

aby po prostu przeglądać katalogi:

 find -path './*' -prune -type d

w celu dołączenia dowiązań symbolicznych w wyniku:

find -L -path './*' -prune -type d

zrobić coś z każdym katalogiem (z wyłączeniem dowiązań symbolicznych):

find -path './*' -prune -type d -print0 | xargs -0 <cmds>

aby wykluczyć ukryte katalogi:

find -path './[^.]*' -prune -type d

aby wykonać wiele poleceń na zwróconych wartościach (bardzo przemyślany przykład):

find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"

zamiast „sh -c” można również użyć „bash -c” itp.


Co się stanie, jeśli echo „* /” in ”dla d in echo * /” zawiera, powiedzmy, 60 000 katalogów?
AsymLabs

Pojawi się błąd „Zbyt wiele plików”, ale można to rozwiązać: Jak obejść „Zbyt wiele otwartych plików” w debian
rubo77

1
Przykład xargs działa tylko dla podzbioru nazw katalogów 9e.g. te ze spacjami lub znakami nowej linii nie będą działać). Lepiej używać, ... -print0 | xargs -0 ...jeśli nie wiesz, jakie są dokładne nazwy.
Anthon

1
@ rubo77 dodał sposób wykluczania ukrytych plików / katalogów i wykonywania wielu poleceń - oczywiście można to zrobić również za pomocą skryptu.
AsymLabs

1
Dodałem przykład w mojej odpowiedzi na dole, jak zrobić coś do każdego katalogu za pomocą funkcji zfind * | while read file; do ...
rubo77

3

Możesz przewijać wszystkie katalogi, w tym ukryte katalogi (zaczynające się od kropki) w jednym wierszu i wiele poleceń za pomocą:

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

Jeśli chcesz wykluczyć dowiązania symboliczne:

for file in *; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

Uwaga: za pomocą listy */ .*/działa w bash, ale również wyświetla foldery, .a ..jednocześnie w zsh nie pokaże tych, ale wygeneruje błąd, jeśli nie ma ukryty plik w folderze

Czystsza wersja, która będzie zawierać ukryte katalogi i wykluczać ../ będzie dostępna z opcją dotglob:

shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done

(lub setopt dotglobw Zsh)

możesz rozbroić dotglob za pomocą

shopt -u dotglob

2

Obejmuje to pełną ścieżkę do każdego katalogu na liście:

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

1
pęka przy korzystaniu z folderów ze spacjami
Alejandro Sazo

0

Użyj za findpomocą, -execaby przeglądać katalogi i wywoływać funkcję w opcji exec:

dosomething () {
  echo "doing something with $1"
}
export -f dosomething
find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \;

Użyj shopt -s dotgloblub, shopt -u dotglobaby włączyć / wyłączyć ukryte katalogi


0

Zawiera listę wszystkich katalogów wraz z liczbą podkatalogów w danej ścieżce:

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- ale zostanie przeanalizowany jako wielokrotność.
Piskvor

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.