dizin boş nasıl kontrol edilir


16

./123Boş bir yol argümanları ile bir komut dosyası yürütmek, bir gereksinim var, /usr/share/linux-headers-3.16.0-34-generic/.tmp_versions(bu dizin boş) deyin . "Dizin boş" yazmalıdır

Kodum:

#!/bin/bash
dir="$1"

if [ $# -ne 1 ]
then
    echo "please pass arguments" 
exit
fi

if [ -e $dir ]
then
printf "minimum file size: %s\n\t%s\n" \
 $(du $dir -hab | sort -n -r | tail -1)

printf "maximum file size: %s\n\t%s\n" \
 $(du $dir -ab | sort -n | tail -1)

printf "average file size: %s"
du $dir -sk | awk '{s+=$1}END{print s/NR}'
else
   echo " directory doesn't exists"
fi

if [ -d "ls -A $dir" ]
 then
    echo " directory is  empty"
fi

Komut dosyası adını yürütürsem ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions(bu dizin boş) gibi bir hata görüntülerim var .

minimum file size: 4096
    /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
maximum file size: 4096
    /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
average file size: 4

sadece çıktıyı göstermek yerine "dizin boş" yukarıdaki çıktıyı gösterir

Eğer betiği doğru argümanlarla aşarsam aşağıdaki çıktı gösterilmelidir (doğru dizin yolu ile kastediyorum). söyle./123 /usr/share

minimum file size: 196
        /usr/share
    maximum file size: 14096
        /usr/share
    average file size: 4000

benim beklenen çıktı: ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions

directory is empty.


birisi lütfen kodumu bir kez kontrol edebilir. Düzenledim
buddha sreekanth

Yanıtlar:


20
if    ls -1qA ./somedir/ | grep -q .
then  ! echo somedir is not empty
else  echo somedir is empty
fi

Yukarıdaki POSIX uyumlu bir testtir ve çok hızlı olmalıdır. lsbir dizindeki istisna .ve ..her satırdaki tüm dosyaları / dizinleri listeler ve çıktıdaki soru işaretiyle birlikte -qtüm yazdırılamayan karakterleri ( \newline'ları da içerecek şekilde) gösterir ?. Bu şekilde grep, girişte tek bir karakter bile alınırsa , true döndürülür - aksi takdirde false olur.

Bunu yalnızca bir POSIX kabuğunda yapmak için:

cd  ./somedir/ || exit
set ./* ./.[!.]* ./..?*
if   [ -n "$4" ] ||
     for e do 
         [ -L "$e" ] ||
         [ -e "$e" ] && break
     done
then ! echo somedir is not empty
else   echo somedir is empty
fi
cd "$OLDPWD"

Bir POSIX kabuk (değil önce devre dışı vardır -filename nesil) olacak ve ardından hazır dizeleri birine konumsal-parametre dizisi , yukarıda ya da başka her birinin sonunda topak operatörler tarafından üretilen alanların için komut. Bunu yapıp yapmamak, globların gerçekten bir şeyle eşleşip eşleşmediğine bağlıdır. Bazı mermilerde, çözülmeyen bir küreye null değerine genişleme talimatı verebilirsiniz - ya da hiç bir şey. Bu bazen yararlı olabilir, ancak taşınabilir değildir ve genellikle özel kabuk seçenekleri ayarlamak ve daha sonra bunları ayarlamak gibi ek sorunlar ile birlikte gelir.set"$@"set

Boş değerli argümanları ele almanın tek taşınabilir yolu ya boş ya da ayarlanmamış değişkenleri ya da ~tilde genişletmeleri içerir. Ve ikincisi, bu arada, öncekinden çok daha güvenlidir.

Kabuğun üstünde, -ebelirtilen üç globtan hiçbiri tek bir eşleşmeden daha fazlasını çözmezse , dosyaların herhangi birini xistence için test eder. Bu nedenle fordöngü, yalnızca üç veya daha az yineleme için ve yalnızca boş bir dizin durumunda veya desenlerden bir veya daha fazlasının yalnızca tek bir dosyaya çözümlenmesi durumunda çalıştırılır. forAyrıca breakglobs herhangi bir gerçek dosyayı temsil eğer s - ve muhtemelen en az muhtemeldir en sırasına göre globs düzenlenmiş gibi, oldukça fazla birinci tekrar her zaman bırakmalısınız.

Her iki durumda da sadece tek bir sistem stat()çağrısı lsiçermelidir - kabuk ve her ikisi de sadece stat()sorgulanan dizine ihtiyaç duymalı ve diş macunlarının içerdiği raporlarını listelemelidir . Bu, findonun yerine stat()listeleyebileceğiniz her dosyanın yerine getireceği davranışla tezattır .


Onaylayabilir. Yazdığım senaryolarda mikeserv'in ilk örneğini kullanıyorum.
Otheus

Bu, var olmayan veya okuma erişimine sahip olmadığınız boş dizinler olarak raporlanır. İkincisi için, okuma erişiminiz varsa ancak arama erişiminiz yoksa, YMMV.
Stéphane Chazelas

@ StéphaneChazelas - belki de, ancak bu tür raporlara kullanıcıyı bu durumu bildirmek için hata mesajları eşlik edecektir.
mikeserv

1
Sadece bu lsdurumda. toplar ve [erişimi olmadığında sessizdir. Örneğin, [ -e /var/spool/cron/crontabs/stephane ]bu ada göre bir dosya varken sessizce yanlış bildirir.
Stéphane Chazelas

Ayrıca somedir bir dizine (veya bir dizine değil) bir simge bağlantısı ise bu çözümlerin eşdeğer olmadığını unutmayın.
Stéphane Chazelas

7

GNU veya modern BSD'lerle findşunları yapabilirsiniz:

if find -- "$dir" -prune -type d -empty | grep -q .; then
  printf '%s\n' "$dir is an empty directory"
else
  printf >&2 '%s\n' "$dir is not empty, or is not a directory" \
                    "or is not readable or searchable in which case" \
                    "you should have seen an error message from find above."
fi

(varsayar $dirbir benzemiyor findyüklem ( !, (, -name...).

POSIXly:

if [ -d "$dir" ] && files=$(ls -qAL -- "$dir") && [ -z "$files" ]; then
  printf '%s\n' "$dir is an empty directory"
else
  printf >&2 '%s\n' "$dir is not empty, or is not a directory" \
                    "or is not readable or searchable in which case" \
                    "you should have seen an error message from ls above."
fi

4

[-z $dir ][-zçoğu sistemde çağrılan komut olmadığından yakınıyor . Köşeli parantezlerin çevresinde boşluklara ihtiyacınız vardır .

[ -z $dir ]eğer gerçek bu dirboş ve çoğu diğer değerleri için yanlıştır dir, ancak örneğin o değeri doğruysa, güvenilmez dirolduğunu = -zya -o -o -n -n. Komut ikameleri için her zaman çift tırnak kullanın (bu, komut dosyanızın geri kalanı için de geçerlidir).

[ -z "$dir" ]değişkenin dirdeğerinin boş olup olmadığını test eder . Değişkenin değeri, dizine giden yol olan bir dizedir. Bu size dizinin kendisi hakkında bir şey söylemez.

Bir dizinin boş olup olmadığını test edecek bir operatör yoktur (normal bir dosya için olduğu gibi ( [ -s "$dir" ]boş olsa bile bir dizin için doğrudur). Bir dizinin boş olup olmadığını test etmenin basit bir yolu, içeriğini listelemektir; boş metin alırsanız, dizin boştur.

if [ -z "$(ls -A -- "$dir")" ]; then 

Yok daha eski sistemlerde ls -Akullanabileceğiniz ls -a, ama sonra .ve ..listelenmiştir.

if [ -z "$(LC_ALL=C ls -a -- "$dir")" = ".
.." ]; then 

( ..Dize, bir satırsonu ve fazladan boşluk değil, sadece bir satırsonu içermesi gerektiğinden, ile başlayan satırı girintilemeyin .)


Lütfen bu bölümü açıklayabilir misiniz "$ (ls -A -" $ dir ")". parantez içinde ve dışında $ ne yapar?
buddha sreekanth


@Giles "$ (ls -A -" $ dir ")" atma hatasını çalışmıyor.
buda sreekanth

@buddhasreekanth Hata nedir? Kopyala yapıştır. Tam olarak ne gözlemlediğinizi açıklamadan “çalışmıyor” derseniz, insanların size yardım etmesini bekleyemezsiniz.
Gilles 'SO- kötü olmayı bırak'

@Giles bu hatadır. Senaryomu yürüttüğümde ./filestats atma hatası .. $ / filestats / home / sreekanth / testdir / aki / schatz minimum dosya boyutu: 4096 / home / sreekanth / testdir / aki / schatz maksimum dosya boyutu: 4096 / home / sreekanth / testdir / aki / schatz ortalama dosya boyutu: 4 dizin boş. "Dizin boş" göstermek yerine. Minimum boyut, maksimum boyut ve ort.
buddha sreekanth

3

Dizinin kendisinin özelliklerine bakıyorsunuz.

$ mkdir /tmp/foo
$ ls -ld /tmp/foo
drwxr-xr-x 2 jackman jackman 4096 May  8 11:32 /tmp/foo
# ...........................^^^^

Orada kaç dosya olduğunu saymak istiyorsunuz:

$ dir=/tmp/foo
$ shopt -s nullglob
$ files=( "$dir"/* "$dir"/.* )
$ echo ${#files[@]}
2
$ printf "%s\n" "${files[@]}"
/tmp/foo/.
/tmp/foo/..

Yani, "dizin boş" için test:

function is_empty {
    local dir="$1"
    shopt -s nullglob
    local files=( "$dir"/* "$dir"/.* )
    [[ ${#files[@]} -eq 2 ]]
}

Bunun gibi:

$ if is_empty /tmp/foo; then echo "it's empty"; else echo "not empty"; fi
it's empty
$ touch /tmp/foo/afile
$ if is_empty /tmp/foo; then echo "it's empty"; else echo "not empty"; fi
not empty

Bu, dizine okuma erişiminiz yoksa veya dizinde yoksa dizinin boş olduğunu bildirir.
Stéphane Chazelas

1

Benim tldr cevabım:

function emptydir {
 [ "$1/"* "" = "" ]  2> /dev/null &&
 [ "$1/"..?* "" = "" ]  2> /dev/null &&
 [ "$1/".[^.]* "" = "" ]  2> /dev/null ||
 [ "$1/"* = "$1/*" ]  2> /dev/null && [ ! -e "$1/*" ] &&
 [ "$1/".[^.]* = "$1/.[^.]*" ]  2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
 [ "$1/"..?* = "$1/..?*" ]  2> /dev/null && [ ! -e "$1/..?*" ]
}

POSIX uyumludur ve çok önemli olmadığı için, dizini listeleyen ve çıktıyı grep'e bağlayan çözümden genellikle daha hızlıdır.

Kullanımı:

if emptydir adir
then
  echo "nothing found" 
else 
  echo "not empty" 
fi

Cevap gibi ben https://unix.stackexchange.com/a/202276/160204 ben yeniden yazmak,:

function emptydir {
  ! { ls -1qA "./$1/" | grep -q . ; }
}

Dizini listeler ve sonucu grep'e yönlendirir. Bunun yerine, glob genişlemesi ve karşılaştırmasına dayanan basit bir işlev öneriyorum.

function emptydir {   
 [ "$(shopt -s nullglob; echo "$1"/{,.[^.],..?}*)" = "" ]
}

Bu işlev standart POSIX değildir ve ile bir alt kabuk çağırır $(). Önce bu basit işlevi açıklarım, böylece nihai çözümü daha iyi anlayabiliriz (yukarıdaki tldr cevabına bakın).

Açıklama:

Genişletme olmadığında sol taraf (LHS) boştur; bu, dizin boş olduğunda geçerlidir. Nullglob seçeneği gereklidir, çünkü aksi takdirde eşleşme olmadığında globun kendisi genişlemenin sonucudur. (Bir LHS glob glob olarak adlandırılan tek bir dosyayla eşleştiğinde oluşan yanlış pozitifler nedeniyle dizin boş olduğunda RHS'nin LHS globlarıyla eşleşmesi çalışmaz: *glob *içindeki dosya dosya adındaki alt dizeyle eşleşir . ) Köşeli ayraç ifadesi {,.[^.],..?}gizli dosyaları kapsar, ancak ..veya içermez ..

Çünkü shopt -s nullglobidam içindedir $()(a altkabuk), bu değişmez nullglobnormalde iyi bir şeydir akım kabuk, seçeneği. Öte yandan, bu seçeneği komut dosyalarında ayarlamak iyi bir fikirdir, çünkü eşleşme olmadığında bir globun bir şey döndürmesi hatalıdır. Böylece, komut dosyasının başında nullglob seçeneği ayarlanabilir ve işlevde gerekli olmayacaktır. Bunu aklımda tutalım: nullglob seçeneğiyle çalışan bir çözüm istiyoruz.

Uyarılar:

Dizine okuma erişimimiz yoksa, işlev boş bir dizin varmış gibi raporlar. Bu, dizini listeleyen ve çıktıyı grep içeren bir işlev için de geçerlidir.

shopt -s nullglobKomut standart POSIX değildir.

Tarafından oluşturulan alt kabuğu kullanır $(). Bu büyük bir anlaşma değil, ama önleyebilirsek güzel.

Pro:

Gerçekten önemli değil, ancak bu işlev, işlem içindeki çekirdeğe harcanan CPU zamanı miktarı ile ölçülen öncekinden dört kat daha hızlıdır.

Diğer çözümler:

Biz olmayan POSIX kaldırabilirsiniz shopt -s nullgloblhs komuta ve dize koymak "$1/* $1/.[^.]* $1/..?*"RHS ve biz sadece adlandırılmış dosyaları olduğunda ayrı ayrı meydana yanlış pozitif ortadan kaldırmak '*', .[^.]*ya da ..?*dizinde:

function emptydir {
 [ "$(echo "$1"/{,.[^.],..?}*)" = "$1/* $1/.[^.]* $1/..?*" ] &&
 [ ! -e "$1/*" ] && [ ! -e "$1/.[^.]*" ] && [ ! -e "$1/..?*" ]
}

shopt -s nullglobKomut olmadan, alt kabuğu kaldırmak mantıklı, ancak dikkatli olmalıyız çünkü kelime bölünmesinden kaçınmak ve yine de LHS'de glob genişlemesine izin vermek istiyoruz. Özellikle kelime bölünmesini önlemek için alıntı yapmak işe yaramaz, çünkü aynı zamanda glob genişlemesini de önler. Çözümümüz globları ayrı ayrı düşünmektir:

function emptydir {
 [ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
 [ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
 [ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}

Tek tek glob için hala kelime bölmemiz var, ama şimdi tamam, çünkü sadece dizin boş olmadığında bir hataya neden olacak. LHS'de verilen glob ile eşleşen birçok dosya olduğunda hata mesajını atmak için 2> / dev / null ekledik.

Nullglob seçeneğiyle de çalışan bir çözüm istediğimizi hatırlıyoruz. Yukarıdaki çözüm nullglob seçeneğiyle başarısız olur, çünkü dizin boş olduğunda, LHS'ler de boştur. Neyse ki, dizinin olmadığı zaman boş olduğunu asla söylemez. Sadece boşken boş olduğunu söyleyemez. Böylece, nullglob seçeneğini ayrı ayrı yönetebiliriz. Durumları [ "$1/"* = "" ]vb. Ekleyemeyiz çünkü bunlar [ = "" ]sözdizimsel olarak yanlış olan, vb. Bunun [ "$1/"* "" = "" ]yerine vs. kullanıyoruz. Biz yine üç kasa düşünmek zorundayız *, ..?*ve .[^.]*gizli dosyaları maç için değil, .ve... Nullglob seçeneğimiz yoksa bunlar karışmaz, çünkü aynı zamanda boş olmadığını da söylemezler. Yani, önerilen son çözüm:

function emptydir {
 [ "$1/"* "" = "" ]  2> /dev/null &&
 [ "$1/"..?* "" = "" ]  2> /dev/null &&
 [ "$1/".[^.]* "" = "" ]  2> /dev/null ||
 [ "$1/"* = "$1/*" ]  2> /dev/null && [ ! -e "$1/*" ] &&
 [ "$1/".[^.]* = "$1/.[^.]*" ]  2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
 [ "$1/"..?* = "$1/..?*" ]  2> /dev/null && [ ! -e "$1/..?*" ]
}

Güvenlik endişesi:

Boş bir dizinde iki dosya oluşturun rmve bilgi isteminde xçalıştırın *. Glob *, genişleyecek rm xve çıkarmak için yürütülecektir x. Bu bir güvenlik kaygısı değildir, çünkü bizim fonksiyonumuzda globlar, genişlemelerin komut olarak değil, argümanlar olarak görüldüğü yerde bulunur for f in *.


$(set -f; echo "$1"/*)oldukça karmaşık bir yazım yolu gibi görünüyor "$1/*". Ve bu gizli dizinlerle veya dosyalarla eşleşmez.
muru

Demek istediğim, dosya adında genişleme olmaması "$1/*"(tırnak işaretleri dahil *), bu nedenle set -fve alt kabuk özellikle bunun için gereksizdir .
muru

Farklı bir soruyu yanıtlar: dizinin gizli olmayan dosyalar veya dizinler içerip içermediği. Bunun için üzgünüm. Silmekten mutluluk duyacağım.
Dominic108

1
Çok gizli dosyaları maç (karmaşık topak görmek için yolu vardır mikeserv cevabı : ./* ./.[!.]* ./..?*). Belki de fonksiyonu tamamlamak için bunu dahil edebilirsiniz.
muru

Ah! Buna bakacağım ve öğreneceğim ve belki de globbing genişlemesine dayalı tam bir cevabımız olacak!
Dominic108

0

İşte bunu yapmanın bir başka basit yolu. D'nin boşluk olup olmadığını test etmek istediğiniz dizinin tam yol adı olduğunu varsayalım.

Sonra

if [[ $( du -s  D |awk ' {print $1}') = 0 ]]
then
      echo D is empty
fi

Bu işe yarıyor çünkü

du -s D

çıktı olarak var

size_of_D   D

awk, D'yi kaldırır ve boyut 0 ise dizin boştur.


-1
#/bin/sh

somedir=somedir
list="`echo "$somedir"/*`"

test "$list" = "$somedir/*" && echo "$somedir is empty"

# dot prefixed entries would be skipped though, you have to explicitly check them

2
Merhaba ve siteye hoş geldiniz. Lütfen sadece kod olan ve açıklama içermeyen cevaplar göndermeyin. Kodu yorumlayın veya başka şekilde ne yaptığınızı açıklayın. Bu arada, kullanmak için hiçbir neden yok echo, tek ihtiyacınız olan şey list="$somedir/*". Ayrıca, bu zor ve hatalara eğilimlidir. OP'nin, örneğin eğik çizgi de dahil olmak üzere hedef direktifin yolunu vermesi gerektiğini söylemediniz.
terdon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.