Wyświetl listę wszystkich katalogów, które NIE zawierają pliku o podanej nazwie


12

Jak powinienem wyświetlić listę wszystkich katalogów, w których nie ma pliku o podanej nazwie? np. biorąc pod uwagę to drzewo

/
  /a
     README
     file001
     file002
  /b
     README
     file001
  /c
     file003

Chcę wymienić katalogi, które nie mają nazwanych plików README, w tym przypadku byłby to katalog /c. Jak mam to zrobić? Nie mogę wymyślić żadnej składni używającej np find.


Wstyd, och, wstyd, że nawet nie szukałeś
slm

Prawdopodobnie nie szukałem odpowiednich słów kluczowych podczas wyszukiwania.
Renan

2
Po prostu walę cię w kotlety. Byłem tam wiele razy, w których nie mogłem znaleźć odpowiedniego słowa, aby wyszukać coś 8-).
slm

Odpowiedzi:


5

Zakładając findimplementację taką jak GNU, findktóra akceptuje {}osadzony w argumencie -exec:

$ find . -type d \! -exec test -e '{}/README' \; -print

Przykład

Tutaj katalogi od 1/1 do 5/5 mają CZYTNIK, pozostałe katalogi są puste.

$ tree 
.
|-- 1
|   `-- 1
|       `-- README
|-- 10
|   `-- 10
|-- 2
|   `-- 2
|       `-- README
|-- 3
|   `-- 3
|       `-- README
|-- 4
|   `-- 4
|       `-- README
|-- 5
|   `-- 5
|       `-- README
|-- 6
|   `-- 6
|-- 7
|   `-- 7
|-- 8
|   `-- 8
`-- 9
    `-- 9

Teraz, gdy uruchomimy tę wersję naszego findpolecenia:

$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2

Bibliografia


Jak zmodyfikować polecenie, aby wyszukać podkatalogi, które nie mają określonego rozszerzenia pliku (powiedzmy * .txt). Modyfikacja pliku README za pomocą * .txt nie działa
WanderingMind

@WanderingMind - jeśli masz nowe pytanie, zadaj je jako nowe na stronie ;-)
slm

3

Możesz użyć -execopcji findsprawdzenia pliku, a następnie wydrukować wszystkie wyniki, dla których sprawdzenie się nie powiedzie.

find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print

3

Nie ma potrzeby find. Wystarczy użyć powłoki:

for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/

Jeśli jest to potrzebne, aby być rekurencyjny, można użyć (na bash, zshmożna to zrobić domyślnie używają set -o globstarw ksh93):

shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done

(zwróć uwagę, że pliki kropek są domyślnie wyłączone).


2

Z kwalifikatoramizsh i glob ( eciąg ):

print -rl -- *(/e_'[[ ! -f $REPLY/README ]]'_)

lub

print -rl -- *(/^e_'[[ -f $REPLY/README ]]'_)

dodaj, Daby uwzględnić ukryte katalogi:

print -rl -- *(D/e_'[[ ! -f $REPLY/README ]]'_)

/wybiera tylko katalogi i e_'[[ ! -f $REPLY/README ]]'_dalej wybiera tylko nazwy katalogów, dla których zwraca kod powłoki między cudzysłowami true, to znaczy dla każdej nazwy katalogu ( $REPLY), do której *(/)rozwija się glob , uruchamia [[ ! -f $REPLY/README ]]i zachowuje nazwę katalogu, jeśli wynik jest true.
Druga forma ^e_'.....'_używa tego samego kwalifikatora globalnego, negowanego (ale tym razem wyrażenie warunkowe nie jest negowane:) [[ -f $REPLY/README ]].


Powyższe zwróci tylko nazwy katalogów w bieżącym katalogu.
Jeśli chcesz wyszukiwać rekurencyjnie (ponownie, aby uwzględnić ukryte katalogi, dodaj Dkwalifikator):

print -rl ./**/*(/e_'[[ ! -f $REPLY/README ]]'_)

2

Przenośnie możesz zrobić:

find . -type d -exec sh -c '
  for dir do
    [ -f "$dir/README" ] || printf "%s\n" "$dir"
  done' sh '{}' +

[ -f file ]sprawdza, czy plik istnieje i czy jest normalny (po rozpoznaniu dowiązania symbolicznego).

Jeśli chcesz przetestować, czy istnieje tylko (jako wpis w tym katalogu), niezależnie od jego typu, potrzebujesz: [ -e file ] || [ -L file ]chociaż pamiętaj, że do wykonania tych testów potrzebujesz uprawnień do wyszukiwania w katalogu. Możesz dodać kilka [ -x "$dir" ]testów, aby uwzględnić takie przypadki, jak:

find . -type d -exec sh -c '
  for dir do
    if [ -x "$dir" ]; then
      [ -f "$dir/README" ] || printf "%s\n" "$dir"
    else
      printf >&2 "Cannot tell for \"%s\"\n" "$dir"
    fi
  done' sh '{}' +

Lub, aby uniknąć wyścigu, stosując zsh:

find . -type d -exec zsh -c '
  zmodload zsh/system
  for dir do
    ERRNO=0
    if [ ! -f "$dir/README" ]; then
      if [ "$errnos[ERRNO]" = ENOENT ]; then
        printf "%s\n" "$dir"
      else
        syserror -p "ERROR: $dir/README: "
      fi
    fi
  done' zsh '{}' +

Zobacz także Jak sprawdzić, czy zwykły plik nie istnieje w Bash? Na tak.

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.