Bash'te normal bir dosyanın bulunmadığını nasıl anlarım?


3263

Bir dosyanın var olup olmadığını görmek için aşağıdaki komut dosyasını kullandım:

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi

Yalnızca dosyanın bulunup bulunmadığını kontrol etmek istiyorsam kullanılacak doğru sözdizimi nedir ?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi


9
Benim çok tembel kişi olarak, genellikle aşağıdaki aptal geçici çözüm yapısını kullanırdım: if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi;Muhtemelen bu soruyu bulduğum ve daha uygun bir şekilde yapmayı öğrendim. :)
Alderath

5
Pendantik olmak için, çoğu UNIX / POSIX dokümanı genel olarak tüm dosya sistemi giriş türlerine genel olarak atıfta bulunduğu için "normal dosya" demelisiniz, örneğin, sembolik bir bağlantı, adlandırılmış bir boru gibi bir dosya türüdür , normal dosya, dizin, özel blok, özel karakter, soket, vb.
kevinarpe

11
@kevinarpe bir şeyin var olup olmadığını test etmek istiyorsanız kullanın -e. -f dizinleri, sembolik bağlantıları vb.
almayacak

14
Güvende olmak için, dosya adlarını boşlukla doğru bir şekilde işlemek için her zaman çift tırnak kullanın, örneğin, FILE=$1-> FILE="$1"ve if [ -f $FILE ];->if [ -f "$FILE" ];
kevinarpe

Yanıtlar:


4523

Test komutu ( [burada) (birçok diğer dillere benzer) ünlem işareti olan bir "not" mantıksal operatör var. Bunu dene:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi

208
Daha özlü: [! -f /tmp/foo.txt] && echo "Dosya bulunamadı!"
DavidWinterbottom

38
"2 dosyadan herhangi biri yoksa" için doğru sözdizimini bulmak için biraz uğraştım. Aşağıdaki her ikisi de çalışır:if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi
mivk

153
@DavidWinterbottom Daha da iyice:[ -f /tmp/foo.txt ] || echo "File not found!"
David W.

27
Parametre aşağıdakilerden herhangi biri olabilir:-e: Returns true value, if file exists -f: Return true value, if file exists and regular file -r: Return true value, if file exists and is readable -w: Return true value, if file exists and is writable -x: Return true value, if file exists and is executable -d: Return true value, if exists and is a directory
SD.

5
Kullanarak bir asimetri vardır ! -file &&kullanarak karşı -folan ||. Bunun, yokluk kontrolü tarafından döndürülen çıkış koduyla ilgilidir. Satırınızın her zaman çıkış kodu 0 ile temiz bir şekilde çıkması gerekiyorsa (ve bazen bu kısıtlamayı istemiyorsanız), iki yaklaşım birbirinin yerine kullanılamaz. Alternatif olarak, sadece bir ififade kullanın ve artık yokluk kontrolünüzün çıkış kodu hakkında endişelenmenize gerek yok.
Acumenus

670

Bash Dosya Testi

-b filename- Özel dosyayı engelle
-c filename- Özel karakter dosyası
-d directoryname- Dizin
-e filenamevarlığını kontrol et - Türden (düğüm, dizin, soket vb.)
-f filenameBağımsız olarak dosya varlığını
-G filenamekontrol edin - Bir dizin değil düzenli dosya varlığını kontrol edin - Dosyanın var olup olmadığını kontrol edin etkin grup kimliği
-G filename set-group-id- Dosya varsa ve set-group-id ise doğrudur
-k filename- Yapışkan bit
-L filename- Sembolik bağlantı
-O filename- Dosya varsa ve etkin kullanıcı kimliğine sahipse doğrudur
-r filename- Dosyanın okunabilir
-S filenameolup olmadığını kontrol edin - Dosyanın soket
-s filenameolup olmadığını kontrol edin - dosya sıfır olmayan boyutta
-u filename- Dosya kümesi-kullanıcı kimliği bitinin ayarlanıp ayarlanmadığını
-w filenamekontrol edin - Dosyanın yazılabilir
-x filenameolup olmadığını kontrol edin - Dosyanın yürütülebilir olup olmadığını kontrol edin

Nasıl kullanılır:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 

Bir test ifadesi! operatör kullanılarak reddedilebilir

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 

1
@ 0x90 İsterseniz yazımı düzenleyebilir ve listeye ekleyebilirsiniz. Yani demek istediğim: -n String- Dize uzunluğunun sıfır olmadığını kontrol edin. Yoksafile1 -nt file2
Dosya1'in

1
-N hakkında: The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty.~ ibm.com/developerworks/library/l-bash-test/index.html
BlueCacti

1
neden bazıları fonksiyon gibi bir fonksiyon eklemedi () {⏎ eğer [-e "$ 1"]; sonra yankı "$ 1 var" başka yankı "$ 1 yok" fi}
Mz A

291

"!" İle ifadeyi reddedebilirsiniz:

#!/bin/bash
FILE=$1

if [ ! -f "$FILE" ]
then
    echo "File $FILE does not exist"
fi

İlgili kılavuz sayfası man testveya eşdeğer olarak man [- veya help testveya help [yerleşik bash komutu içindir.


4
In Bash , [bir yerleşik olduğunu. Böylece ilgili bilgi daha çok elde edilir help [... ama bu, yerleşikin [eşanlamlı olduğunu gösterir test, bu nedenle ilgili bilgi daha çok elde edilir help test. Ayrıca kılavuzdaki Bash Koşullu İfadesi bölümüne bakın .
gniourf_gniourf

@gniourf_gniourf: Evet, ancak bash yerleşik [komutu harici [komutla çok benzer şekilde davranır , bu nedenle ya nasıl çalıştığı hakkında iyi bir fikir verir man testveya man [verir.
Keith Thompson

8
O hariç @KeithThompson bash yerleşik [dış komut daha fazla anahtarı vardır [Genellikle bunun belgeleri belirli bir alete özgü değil, başka belli belirsiz ilgili birine dokümantasyon özgü okumak için daha iyi olduğuna inanıyorum konuşan ... sistemimde bulundu. Yine de yanlış olabilir;)
gniourf_gniourf

134
[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"

Ayrıca, dosyanın bozuk bir sembolik bağlantı veya soket, aygıt veya fifo gibi normal olmayan bir dosya olması mümkündür. Örneğin, bozuk sembolik bağlantılar için bir kontrol eklemek için:

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi

9
Testteki iki "[" nin neden olduğunu sorabilir miyim? (örneğin [[! -a $ FILE]]). Bir solaris kutusunda belirtilen tüm seçenekleri denedim ve sadece biri çalıştı, çok minnettar, ama neden?
Dimitrios Mistriotis

30
Çift parantez "modern" bir eklentidir; örneğin, kelime bölme (boşluklu dosya adları gibi) yapmazlar
bw1024

7
tldp.org/LDP/abs/html/fto.html -a'ya göre -e ile aynıdır. "Kullanımdan kaldırıldı" ve kullanımı önerilmez. Her neyse +1 kırık symlink kontrol de bahsettiğiniz için
Luca Borrione

4
@dimitrismistriotis iki "[", zsh & bash tarafından uygulanan (farklı) taşınabilir olmayan bir uzantıdır; Genellikle mümkünse bundan kaçınmalısınız.
İyi Kişi

7
Ben kullandığı bu ÇÜNKÜ oy [[. Yaygın olarak kullanılan bir uzantıdır. Eğer bash kullandığınızı biliyorsanız, kullanmamanız için hiçbir neden yoktur. Hata eğilimi ['den çok daha azdır.
Michael Potter

101

Tek bir komut yürütmeniz gerekiyorsa kısaltabileceğinizi belirtmek gerekir.

if [ ! -f "$file" ]; then
    echo "$file"
fi

için

test -f "$file" || echo "$file"

veya

[ -f "$file" ] || echo "$file"

Teşekkürler! Kullanmayan bir alternatif gerekli [[]]
Jonathan

69

POSIX kabuğu uyumlu biçimde aşağıdaki tek astarı yapmayı tercih ederim :

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"

Bir komutta yaptığım gibi birkaç komut için:

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}

Bunu yapmaya başladıktan sonra artık nadiren tam yazım sözdizimini kullanıyorum !!


1
Her şeyden önce, alıntılanmamış değişken referansları hataya açıktır. Bununla birlikte, herhangi bir bash manpageinde, yerleşik [veya testyerleşik öğenin varsayılan olarak (aksine ) argümanın dosya varlığını test edeceğini söylüyor -e? Bu belirsiz olmaz mı? AFAIK (ve AIUI bölümü "KOŞULLU ANLATIMLAR") yaklaşımınızla test edilen tek şey, argümanın boş (veya tanımsız) olmadığı, bu durumda bir totolojinin (hadi $DIR = ''ve $FILE = ''sonra argüman hala '//').
PointedEars

1
İspat: ls /foosonuç ls: cannot access /foo: No such file or directory. [ /foo ] && echo 42, sonuç 42. GNU bash, sürüm 4.2.37 (1) -çalışma (i486-pc-linux-gnu).
PointedEars

@PointedEars: -fSeçeneği belirleyemedim , şu anda bu cevabı yazdım. Açıkçası her zaman kullanabilirsiniz -e, eğer emin değilseniz normal bir dosya olacaktır. Ayrıca tüm senaryolarımda bu yapıları alıntıladım, bunu yeterli bir kanıt olmadan göndermeliydim.
JM Becker

ACK. Ama muhtemelen bir astarın if-else problemini çözemediğini biliyorsunuz: [ $condition ] && if_true || if_falsehataya açık. Her halükarda, [ ! -f "$file" ] && if_not_existsokumayı ve anlamayı daha kolay buluyorum [ -f "$file" ] || if_not_exists.
12:33

55

Dosya varlığını test etmek için parametre aşağıdakilerden herhangi biri olabilir:

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink

Aşağıdaki tüm testler normal dosyalar, dizinler ve semboller için geçerlidir:

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0

Örnek komut dosyası:

#!/bin/bash
FILE=$1

if [ -f "$FILE" ]; then
   echo "File $FILE exists"
else
   echo "File $FILE does not exist"
fi

39

Bunu yapabilirsiniz:

[[ ! -f "$FILE" ]] && echo "File doesn't exist"

veya

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi

Her iki dosyayı ve klasörü kontrol etmek istiyorsanız, -eyerine seçeneğini kullanın -f. -enormal dosyalar, dizinler, soket, karakter özel dosyaları, blok özel dosyaları vb.


1
Bu bash'e özgü değil. Sözdizimi Korn kabuğundan gelir ve zsh ve bash olarak da kullanılabilir. [Buradaki standart faydaya göre sınırlı bir avantajı vardır .
Stephane Chazelas

normal dosyalar (kontrol edildiği gibi -f) ve dizinler birçok farklı dosya türünden sadece ikisidir . Ayrıca soketler, semboller, cihazlar, fifos, kapılar ... symlink çözünürlüğünden sonra[ -e dosya varlığını (normal, fifo, dizin ... dahil olmak üzere herhangi bir türde) test eder .
Stephane Chazelas

@StephaneChazelas: Hiçbir yerde ksh veya zsh etiketi görmüyorum. Bash veya çoğu unix sisteminde standartlaştırılmış bir şeyden bahsediyoruz. Yani, bağlam içinde, bu bash'e özgüdür. OP, orada ne olursa olsun mermileri bilmek zorunda değil: D
Jahid

Bu, cevabınızın "Bash'a özgü" kısmına yapılan bir yorumdu.
Stephane Chazelas

@StephaneChazelas: Evet ve bağlam içinde (bash ve standart sh), bash'a özgüdür. İkinci yorumunuzdaki noktayı görmüyorum, tamamen bağlam dışı. OP'nin ihtiyacı yok -e, ihtiyacı var -f.
Jahid

35

testBeklenmedik sonuçlar doğurabileceğinden, sıralanmamış bir değişken için çalıştırma konusunda dikkatli olmalısınız :

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

Öneri genellikle test edilen değişkenin çift tırnak işareti içine alınmasıdır:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi

8
Gereksiz olduğu nadir durumlardan birine veya zararlı olduğu daha nadir vakalardan birine sahip olduğunuzu tam olarak bilmediğiniz sürece , her değişkenin çift tırnak işareti ile çevrelenmesi önerilir . (Ve hayır, bu onlardan biri değil.)
Uwe

Çift tırnak işareti kullanmanın neden böyle olmadığını açıklamak ister misiniz? Aksi takdirde yorumda fayda görmüyorum.
artdanil

4
Demek istediğim: Bu, gereksiz veya zararlı olduğu nadir durumlardan biri değil. Bir kabuk programcısı her değişkeni çift tırnak içine almak (neredeyse) için kullanılmalıdır; bu kuralla sınırlı değildir [ ... ].
Uwe


24

Bunu yapmanın üç farklı yolu vardır:

  1. Çıkış durumunu bash ile kısaltın (bunu başka bir yanıt söylemedi):

    if ! [ -e "$file" ]; then
        echo "file does not exist"
    fi

    Veya:

    ! [ -e "$file" ] && echo "file does not exist"
  2. Testi test komutunun içine alın [(daha önce cevapların çoğunun sunma şekli):

    if [ ! -e "$file" ]; then
        echo "file does not exist"
    fi

    Veya:

    [ ! -e "$file" ] && echo "file does not exist"
  3. Testin negatif ( ||yerine &&) sonucuna göre hareket edin :

    Bir tek:

    [ -e "$file" ] || echo "file does not exist"

    Bu aptalca görünüyor (IMO), kodunuzun /bin/shboru hattı olumsuzlama operatörüne ( !) sahip olmayan Bourne kabuğuna ( Solaris 10 veya öncesi gibi) taşınabilir olması gerekmediği sürece kullanmayın :

    if [ -e "$file" ]; then
        :
    else
        echo "file does not exist"
    fi

! [Ve [ !? Arasında herhangi bir taşınabilirlik farkı var mı?
Donmuş Alev

3
! [ Kabuk boru hatları 2.9.2 (herhangi bir komut) için POSIX Otherwise, the exit status shall be the logical NOT of the exit status of the last command ve [ ! test için POSIX olan ! expression True if expression is false. False if expression is true. hem POSIX, ve benim deneyim, hem yoğun desteklenmektedir Yani.

1
@FrozenFlame, Bourne kabuğu !Korn kabuğu tarafından tanıtılan anahtar kelimeye sahip değildi. Belki Solaris 10 ve üstü hariç, bugünlerde bir Bourne kabuğuyla karşılaşmanız pek mümkün değil.
Stephane Chazelas

22

İçinde

[ -f "$file" ]

[komutu bir does stat()(değil lstat()saklanan yolda) sistem çağrısını $fileve döndüren gerçek sistem çağrısı başarılı olursa ve dosya türü tarafından döndürülen olarakstat() "dir düzenli ".

Yani eğer [ -f "$file" ] true döndürürse, dosyanın var olduğunu ve normal bir dosya veya sonunda normal bir dosyaya çözümlenen bir symlink olduğunu söyleyebilirsiniz (veya en azından o sıradaydı stat()).

Ancak yanlış döndürürse (veya[ ! -f "$file" ] veya ! [ -f "$file" ]return true), birçok farklı olasılık vardır:

  • dosya mevcut değil
  • dosya var ama bir normal bir dosya (bir cihaz, fifo, dizin, soket olabilir ...)
  • dosya var ancak üst dizine arama izniniz yok
  • dosya var, ancak dosyaya erişmek için gereken yol çok uzun
  • dosya normal bir dosyaya bir simge bağlantısıdır, ancak simge bağlantısının çözümüne dahil olan bazı dizinler için arama izniniz yoktur.
  • ... stat()sistem çağrısının başarısız olmasının başka nedenleri .

Kısacası, şöyle olmalıdır:

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi

Dosyanın bulunmadığından emin olmak için, stat()sistem çağrısının hata koduyla geri dönmesi gerekir ENOENT( ENOTDIRyol bileşenlerinden birinin dizin olmadığını söyler, dosyanın olmadığını söyleyebileceğimiz başka bir durumdur bu yol tarafından var). Ne yazık ki [komut bunu bize bildirmiyor. Hata kodu ENOENT, EACCESS (izin reddedildi), ENAMETOOLONG veya başka bir şey olsun, yanlış döndürür.

[ -e "$file" ]Test ayrıca ile yapılabilir ls -Ld -- "$file" > /dev/null. Bu durumda, bilgiler lsneden stat()başarısız olduğunu söyleyecektir , ancak bilgiler programlı olarak kolayca kullanılamaz:

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed

En azından lsbana bunun başarısız olduğu için dosya olmadığı için olmadığını söylüyor. Çünkü dosyanın var olup olmadığını söyleyemez. [Komut sadece sorunu görmezden geldi.

İle zshkabuk, sizinle hata kodunu sorgulayabilir $ERRNOözel başarısız sonra değişkenin [komuta ve sayı kullanarak o kod çözme $errnosözel dizi zsh/systemmodülü:

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi

(en son sürümleriyle oluşturulduğunda $errnosdesteğin bazı sürümleriyle bozulduğunazshgcc dikkat edin ).


11

Testi tersine çevirmek için "!" Kullanın. Bu, diğer dillerde "değil" mantıksal operatörüne eşdeğerdir. Bunu dene:

if [ ! -f /tmp/foo.txt ];
then
    echo "File not found!"
fi

Ya da biraz farklı bir şekilde yazılmış:

if [ ! -f /tmp/foo.txt ]
    then echo "File not found!"
fi

Veya şunları kullanabilirsiniz:

if ! [ -f /tmp/foo.txt ]
    then echo "File not found!"
fi

Veya hepsini bir araya getirerek:

if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi

Hangisi yazılabilir (o zaman "ve" operatörü: &&):

[ ! -f /tmp/foo.txt ] && echo "File not found!"

Bu daha kısa görünüyor:

[ -f /tmp/foo.txt ] || echo "File not found!"


10

Bu kod da çalışıyor.

#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
 echo "File '$FILE' Exists"
else
 echo "The File '$FILE' Does Not Exist"
fi

7

En basit yol

FILE=$1
[ ! -e "${FILE}" ] && echo "does not exist" || echo "exists"

6

Bu kabuk betiği dizindeki bir dosyayı bulmak için de çalışır:

echo "enter file"

read -r a

if [ -s /home/trainee02/"$a" ]
then
    echo "yes. file is there."
else
    echo "sorry. file is not there."
fi

3
Bunun, diğer yanıtların henüz vermediği bir şey eklediği açık değildir. Bir yol adını sabit kodlar. Soru bash olarak etiketlendiğinden , hem sormak read -p "Enter file name: " -r ahem de okumak için kullanılabilir. Değişkenin etrafında tırnak işaretleri kullanır; bu iyi, ama açıklanmalıdır. Dosya adını yankılarsa daha iyi olabilir. Bu da dosyanın var olup olmadığını ve boş olmadığını kontrol eder (anlamı budur -s), oysa soru boş veya değil ( -fdaha uygun olan) herhangi bir dosya hakkında soru sorar .
Jonathan Leffler

4

bazen && ve || kullanmak kullanışlı olabilir operatörler.

İçinde olduğu gibi ("test" komutunuz varsa):

test -b $FILE && echo File not there!

veya

test -b $FILE || echo File there!

2

testBunun yerine kullanmak istiyorsanız , olumsuzlamayı almak için []kullanabilirsiniz !:

if ! test "$FILE"; then
  echo "does not exist"
fi

0

Tek bir astarda birden çok komutu da gruplayabilirsiniz

[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )

veya

[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}

Dosya adı çıkmazsa, çıktı

test1
test2
test3

Not: (...) bir alt kabukta, {...;} aynı kabukta çalışır. Kıvırcık parantez gösterimi yalnızca bash'da çalışır.


1
Hayır, süslü ayraç gösterimi sadece bash değildir ; POSIX uyumlu herhangi bir kabukta çalışır.
Charles Duffy

0
envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi

Lütfen kodla birlikte bir açıklama sağlayın.
zohar

Bu kod OP sorununu çözse de, kodunuzun OP sorununu nasıl ele aldığına dair bir açıklama eklemek en iyisidir. Bu şekilde, gelecekteki ziyaretçiler yayınınızdan bilgi edinebilir ve kendi kodlarına uygulayabilir. SO bir kodlama servisi değil, bilgi kaynağıdır. Ayrıca, yüksek kaliteli ve eksiksiz cevapların kaldırılması daha olasıdır. Bu özellikler, tüm yayınların bağımsız olması şartıyla birlikte, bir platform olarak SO'yu forumlardan ayıran güçlü yönlerinden bazılarıdır. Ek bilgi eklemek ve / veya açıklamalarınızı kaynak belgelerle desteklemek için düzenleyebilirsiniz.
ysf
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.