Bash komut dosyası: boş bir dizin için test


95

Bir dizinde herhangi bir dosya bulunup bulunmadığını test etmek istiyorum. Eğer öyleyse, bazı işlemleri atlayacağım.

Aşağıdakileri denedim:

if [ ./* == "./*" ]; then
    echo "No new file"
    exit 1
fi

Bu aşağıdaki hatayı veriyor:

line 1: [: too many arguments

Bir çözüm / alternatif var mı?


Yanıtlar:


121
if [ -z "$(ls -A /path/to/dir)" ]; then
   echo "Empty"
else
   echo "Not Empty"
fi

Ayrıca, dizinin daha önce var olup olmadığını kontrol etmek iyi olurdu.


11
Kullanmayın &&ve ||aynı anda! Eğer echo "Not Empty"başarısız echo "Empty"çalışacak! Dene echo "test" && false || echo "fail"! Evet, echobaşarısız olmayacağını biliyorum ama başka bir komutu değiştirirseniz, sürpriz olacaksınız!
uzsolt

4
Lütfen yukarıdaki kod çalışmadığında en az bir örnek verin. Somut olarak bu kod kesinlikle doğru. Umarım, asker bunu kendi amaçları için uyarlayabilir
Andrey Atapin

3
[ "$(ls -A /)" ] && touch /non-empty || echo "Empty"- Boş olmayan dizleri oluşturulmuş bir dosyayla "işaretlemek" istiyorsanız non-empty, başarısız olur ve "Boş" olarak yazdırır.
uzsolt

4
nerede touch /emptybenim doğrultusunda?
Andrey Atapin

7
Oh hayır! Bu kodla ilgili çok önemli bir sorun var. Olması gereken if [ -n "$(ls -A /path/to/dir)" ]; then... Lütfen birileri bu kodu bir yere sunucularına yapıştırmadan önce cevabı güncelleyin ve bir bilgisayar korsanı nasıl yararlanabileceğini anlayamadı. Eğer /path/to/dirboş değil, o zaman dosya adları var argümanlar olarak geçti almak için /bin/testhangi açıkça tasarlanmamıştır. Sadece -nargümanı ekleyin , problem çözüldü. Teşekkürler!
Edward Ned Harvey,

21

Bir şey saymaya gerek yok, ya da kabuk topaklar. readİle birlikte de kullanabilirsiniz find. Eğer findbireyin çıktı boştur, sen dönersiniz false:

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

Bu taşınabilir olmalı.


Güzel bir çözüm, ancak echoçağrılarınızın yanlış sonucu yansıttığını düşünüyorum : testimde (Cygwin altında) find . -mindepth 1 | readboş olmayan bir direkte 141 hata kodu ve boş bir direkte 0
Lucas Cimon

@LucasCimon Burada değil (macOS ve GNU / Linux). Bir boş olmayan dizine için read0 döndürür ve boş biri için, 1.
slhck

1
PSA ile çalışmıyorset -o pipefail
Albay Thirty Two

19
if [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi

Doğru ve hızlı. Güzel!
lbb0

4
Tırnaklara (2x) ve testin -ndoğru ve güvenli olması gerekiyor (adında boşluk bulunan bir dizini test edin, '0 = 1' adında boş olmayan bir dizinle test edin). ... [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; ...
Zrin

1
@ ivan_pozdeev Bu doğru değil, en azından GNU bulmak için. Düşünüyor olabilirsiniz grep. serverfault.com/questions/225798/…
Vladimir Panteleev

Yazmak daha kolay olabilir find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty | grep .ve grep'ten çıkış durumuna güvenebilirsiniz. Hangi şekilde yaparsanız yapın, bu sorunun cevabı çok doğru.
Tom Anderson,

13
#!/bin/bash
if [ -d /path/to/dir ]; then
    # the directory exists
    [ "$(ls -A /path/to/dir)" ] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [ -f /path/to/dir]
fi

4
Öyle olmalı, çıktısını ayrıştırmaya gerek yok, sadece boş mu değil mi bakın. Find'ı kullanmak, bana aşırı saygın gibi geliyor.
akostadinov

4

Bu, geçerli çalışma dizininde (.) İşi yapacak:

[ `ls -1A . | wc -l` -eq 0 ] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

veya aynı komut sadece daha okunaklı olmak üzere üç satıra bölündü:

[ `ls -1A . | wc -l` -eq 0 ] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

Farklı bir hedef klasörde çalıştırmanız gerekirse, sadece ls -1A . | wc -lbununla değiştirin ls -1A <target-directory> | wc -l.

Düzenleme : Ben yerini -1aile -1A(@Daniel yorumunu bakınız)


2
kullanmak ls -Ayerine. Bazı dosya sistemlerinin dokümanlara göre .ve ..sembolik bağları yoktur.
Daniel Beck

1
Teşekkürler @Daniel, önerinizden sonra cevabımı düzelttim. "1" in de kaldırılabileceğini biliyorum.
ztank1013

2
Acıtmaz, ancak bir terminale çıkarmazsa ima edilir. Başka bir programa aktardığınızdan, gereksiz.
Daniel Beck

-1kesinlikle gereksiz. Borulandığında lssatır başına bir öğe basmasa bile, sıfır veya daha fazla satır üretip üretmediğini kontrol etme fikrini etkilemez.
Victor Yarema

3

Aşağıdakileri kullanın:

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [ $count -eq 0 ] ; then
   echo "No new file"
   exit 1
fi

Bu şekilde, çıktı biçiminden bağımsızsınız ls. -mindepthdizini atlar, -maxdepthişleri hızlandırmak için alt dizinlere yinelenerek savunmayı önler.


Tabii ki, şimdi bağımlı wc -lve findçıktı formatı (ki oldukça basit olsa da).
Daniel Beck

3

Bir dizi kullanarak:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi

3
Çok güzel bir çözüm, ancak gerekli olduğunu unutmayınshopt -s nullglob
xebeche

3
${#files[@]} == 2Varsayım kök dir için durmazsa (o boş ama eğer muhtemelen test etmeyecektir o sınırlama olabilir bilmediği bazı kodu).
ivan_pozdeev

3

Korsan, ancak yalnızca baska, PID'siz bir yol:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1)   return 0 ;;
        *)   return 1 ;;
    esac
}

Bu, testdaha sonra birden fazla argüman verilirse , yerleşimin 2 ile çıkması gerçeğinden yararlanır -e: İlk önce, "$1"/*küre bash ile genişletilir. Bu, dosya başına bir argümanla sonuçlanır. Yani

  • Dosya test -e "$1"*yoksa , yıldız işareti genişlemez, bu nedenle Shell *, 1 adındaki dosyayı denemeye geri döner.

  • ... aslında tam olarak adlandırılmış bir dosya varsa *, o zaman yıldız işareti, yani yukarıdaki ile aynı çağrı ile biten, yıldıza kadar genişler. test -e "dir/*", sadece bu kez 0 döndürür. (Bunu işaret ettiğin için @TrueY teşekkürler.)

  • Bir dosya varsa, test -e "dir/file"0 döndüren çalıştırılır.

  • Fakat eğer 1'den daha fazla dosya varsa test -e "dir/file1" "dir/file2" çalıştırılır, bu da bash bunu kullanım hatası olarak rapor eder, yani 2.

case Tüm mantığı etrafına sararak, yalnızca ilk durumda, 1 çıkış durumu ile başarı olarak rapor edilir.

Kontrol edemediğim olası sorunlar:

  • İzin verilen bağımsız değişkenlerin sayısından daha fazla dosya var - Sanırım bu, 2+ dosyada olduğu gibi olabilir.

  • Veya aslında boş bir isme sahip bir dosya var - herhangi bir işletim sistemi / FS'de bunun mümkün olduğundan emin değilim.


1
Küçük düzeltme: / dizininde dosya yoksa test -e dir/*, denir. Eğer tek dosya dir '*' ise o zaman test 0 döndürür. Eğer daha fazla dosya varsa, o zaman 2 döndürür.
TrueY

Haklısın, @TrueY, cevabına dahil ettim. Teşekkürler!
Alois Mahdal

2

FIND (1) ile (Linux ve FreeBSD altında), "-maxdepth 0" üzerinden bir dizin girişine özyinelemesiz bakabilir ve "-empty" ile boş olup olmadığını test edebilirsiniz. Bu verilen soruya uygulanır:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi

% 100 taşınabilir olmayabilir, ancak şık.
Craig Ringer

1

Bence en iyi çözüm:

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[[ "$files" ]] || echo "dir empty" 

https://stackoverflow.com/a/91558/520567 sayesinde

Bu, cevabımın birisine yardımcı olabilecek veya etmeyebilecek isimsiz bir düzenlemedir: Hafif bir değişiklik dosya sayısını verir:

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

Dosya isimleri boşluklar içerse bile bu doğru çalışacaktır.


1
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

EDIT: Bu çözümün uygulamaya hızlı bir bakıştan sonra gnu find ile iyi çalıştığını düşünüyorum . Ancak bu, örneğin netbsd'nin bulduğu ile çalışmayabilir . Aslında, bu bir stat (2) 'nin st_size alanını kullanır. El kitabında şöyle açıklanmaktadır:

st_size            The size of the file in bytes.  The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory.  Some may also return other
                   things or always report zero.

Daha iyi bir çözüm, aynı zamanda daha basit:

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

Ayrıca, ilk çözümdeki -prune işe yaramaz.

EDIT: hayır-gnu bulmak için-çıkış yok .. yukarıdaki çözüm NetBSD bulmak için iyidir. GNU bulmak için bu çalışması gerekir:

if [ -z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`" ]; then
    echo Empty
else
    echo Not Empty
fi

bulmak dan GNU findutils 4.6.0 (son sürüm) bir yok -exityüklemi .
Dennis,

0

Bunların hepsi harika bir şey - sadece bir betiğe dönüştürdüm, böylece şu anki dizinin altındaki boş dizinleri kontrol edebilirim. Aşağıdakiler bash bulmasını sağlayacak şekilde yolun içine yerleştirilmiş olan 'findempty' adında bir dosyaya koyulmalı ve ardından chmod 755'i çalıştırmalı. Sanırım sizin özel ihtiyaçlarınıza göre kolayca değiştirilebilir.

#!/bin/bash
if [ "$#" == "0" ]; then 
find . -maxdepth 1 -type d -exec findempty "{}"  \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if [ "$COUNT" == "0" ]; then 
echo "$* : $COUNT"
fi

0

Bu benim için çalışır, dizindeki dosyaları kontrol etmek ve işlemek için ../INkomut dosyası ../Scriptdizindedir:

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code

0

Dizin varsa ve bir if ifadesinde boş değilse sınama hakkında ne

if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi

-1

Geçerli olandan farklı bir dizin rmdiriçin, rmdirboş olmayan dizinlerde başarısız olma garantili olduğundan , boşalıp denemekten boş olup olmadığını kontrol edebilirsiniz . rmdirBaşarılı olursa ve aslında boş dizinin testte hayatta kalmasını istediniz, sadece mkdirtekrar.

Bu kesmeyi, kısaca sona erme hakkında bildikleri bir dizin tarafından rahatsız edilebilecek başka işlemler varsa kullanmayın.

Eğer rmdirsizin için çalışmaz ve potansiyel çok sayıda dosya, yavaş almak ve / veya komut satırı uzunluğu sınırları içine çalıştırabilir kabuk Genellemenin güvenerek herhangi bir çözüm içerebilir dizinleri test ediyor. findBu durumda kullanmak muhtemelen daha iyi . findAklıma gelen en hızlı çözüm

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

Bu GNU ve BSD versiyonları için çalışıyor, findancak bu findoperatörlerin her birini eksik olan Solaris için değil . İşini seviyorum, Oracle.


İyi bir fikir değil. OP, dizinin boş olup olmadığını test etmek istedi.
roaima

-3

Dizini kaldırmayı deneyebilir ve bir hata bekleyebilirsiniz; Boş değilse, rmdir dizini silmez.

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path        # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi

3
-1 Bu, geri tepen kod türüdür. rmdirdizini kaldırma iznim yoksa başarısız olur; veya eğer bir Btrfs alt hacmi ise; veya salt okunur bir dosya sistemine aitse. Ve rmdirbaşarısız olmaz ve mkdirçalışırsa: ya önceden kaldırılmış olan dizin başka bir kullanıcıya aitse? peki ya (muhtemelen standart dışı) izinler? ACL? genişletilmiş öznitelikler? Hepsi kayboldu.
Kamil Maciorowski

Eh, sadece bash öğreniyorum ve tüm dizini yinelemekten ziyade daha hızlı bir yol olabileceğini düşündüm, ancak CPU'lar güçlü ve haklısınız, güvenli değilsiniz.
impxd
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.