Pytanie Jak sprawdzić, czy zwykły plik nie istnieje w Bash?


Użyłem następującego skryptu, aby sprawdzić, czy plik istnieje:

#!/bin/bash

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

Jaka jest prawidłowa składnia do użycia, jeśli chcę tylko sprawdzić, czy plik nie działa nie istnieć?

#!/bin/bash

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

2518
2018-03-12 14:48


pochodzenie


Znalazłem to lista instrukcji warunkowych bashbardzo przydatne. - Saulius Žemaitaitis
Będąc bardzo leniwą osobą, którą ja jestem, zazwyczaj używałbym poniższej, niemądrej konstrukcji: if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi; Prawdopodobnie dobrze, że znalazłem to pytanie i nauczyłem się robić to w bardziej odpowiedni sposób. :) - Alderath
Aby być pendantycznym, powinieneś powiedzieć "zwykły plik", ponieważ większość dokumentów UNIX / POSIX ogólnie odnosi się do wszystkich typów wpisów w systemie plików po prostu "pliki", np. Dowiązanie symboliczne jest rodzajem pliku, tak jak nazwana potok , zwykły plik, katalog, blok specjalny, znak specjalny, gniazdo itp. - kevinarpe
@kevinarpe, jeśli chcesz sprawdzić, czy coś istnieje, użyj -e. -f nie będzie pobierał katalogów, dowiązań symbolicznych itp. - Benubird
Aby być bezpiecznym, zawsze używaj podwójnych cudzysłowów, aby poprawnie obsługiwać nazwy plików za pomocą białych znaków, np. FILE=$1 -> FILE="$1" i if [ -f $FILE ]; -> if [ -f "$FILE" ]; - kevinarpe


Odpowiedzi:


The test dowództwo ([ tutaj) ma "nie" operator logiczny, który jest wykrzyknikiem (podobnie jak wiele innych języków). Spróbuj tego:

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

3529
2018-03-12 14:50



Trochę się zmagałem, aby znaleźć odpowiednią składnię "jeśli któryś z 2 plików nie istnieje". Poniższe obie prace: if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi  if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi - mivk
@DavidWinterbottom Jeszcze bardziej soczyście: [ -f /tmp/foo.txt ] || echo "File not found!" - David W.
Parametr może być jednym z poniższych: -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.
Jeśli chcesz użyć 2 warunków w operacjach typu "I", użyj operatora -a, to znaczy AND. Myślę, że jest to również możliwe w przypadku korzystania z operatora [[]] - GroundZero
Występuje asymetria w użyciu ! -f z && kontra użycie -f z ||. Ma to związek z kodem wyjścia zwróconym przez kontrolę nieistnienia. Jeśli potrzebujesz, aby twoja linia zawsze kończyła się czysto z kodem wyjścia 0 (i czasami nie chcesz tego ograniczenia), te dwa podejścia nie są wymienne. Alternatywnie, po prostu użyj if oświadczenie i nie musisz już martwić się o kod zakończenia kontroli nieistnienia. - A-B-B


Testowanie plików Bash

-b filename - Zablokuj specjalny plik
-c filename - Specjalny plik postaci
-d directoryname - Sprawdź katalog Istnienie
-e filename - Sprawdź, czy plik istnieje, niezależnie od typu (węzeł, katalog, gniazdo itp.)
-f filename - Sprawdź, czy zwykły plik nie jest katalogiem
-G filename - Sprawdź, czy plik istnieje i czy jego właścicielem jest efektywny identyfikator grupy
-G filename set-group-id - Prawda, jeśli plik istnieje i ma ustawiony identyfikator grupy-zestawu
-k filename - Przyklejony bit
-L filename - Link symboliczny
-O filename - Prawda, jeśli plik istnieje i jest własnością efektywnego identyfikatora użytkownika
-r filename - Sprawdź, czy plik jest czytelny
-S filename - Sprawdź, czy plik jest gniazdem
-s filename - Sprawdź, czy plik ma rozmiar inny niż zero
-u filename - Sprawdź, czy bit set-user-id jest ustawiony
-w filename - Sprawdź, czy plik jest zapisywalny
-x filename - Sprawdź, czy plik jest wykonywalny

Jak używać:

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

ZA wyrażenie testowe można zanegować za pomocą ! operator

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

429
2018-01-16 14:25



@ 0x90 Jeśli chcesz, możesz edytować mój wpis i dodać go do listy. Chyba masz na myśli: -n String - Sprawdź, czy długość struny nie wynosi zero. Czy masz na myśli? file1 -nt file2 - Sprawdź, czy plik1 jest nowszy, a następnie plik 2 (możesz także użyć -ot dla starszych niż) - GroundZero
Informacje o -n: 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 - GroundZero


Możesz negować wyrażenie za pomocą "!":

#!/bin/bash
FILE=$1

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

Odpowiednią stroną podręcznika jest man test lub, równoważnie, man [ - lub help test lub help [ dla wbudowanego polecenia bash.


250
2018-03-12 14:50



W grzmotnąć, [ jest wbudowany. Tak więc odpowiednie informacje są raczej uzyskiwane przez help [... ale to pokazuje [ jest synonimem test wbudowane, stąd odpowiednie informacje są raczej uzyskiwane przez help test. Zobacz także Sekcja Wyrażenie warunkowe Bash w podręczniku. - gniourf_gniourf
@ Gniourf_gniourf: Tak, ale wbudowany bash [ polecenie zachowuje się bardzo podobnie do zewnętrznego [ polecenie, więc albo man test lub man [ da ci dobry pomysł, jak to działa. - Keith Thompson
@ KeeThompson z wyjątkiem tego grzmotnąć wbudowany [ ma więcej przełączników niż polecenie zewnętrzne [ znalezione w moim systemie ... Ogólnie uważam, że lepiej jest przeczytać dokumentację specyficzną dla danego narzędzia, a nie dokumentację specyficzną dla innej, niejasno powiązanej. Jednak mogę się mylić ;) - gniourf_gniourf


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

Możliwe też, że plik jest uszkodzonym dowiązaniem symbolicznym lub nieregularnym plikiem, np. gniazdo, urządzenie lub fifo. Na przykład, aby dodać sprawdzenie uszkodzonych dowiązań symbolicznych:

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

110
2018-03-12 14:52



Czy mogę zapytać, dlaczego te dwa "[są w teście? (np. [[! -a $ FILE]]). Wypróbowałem wszystkie opcje wymienione na pudełku solaris i tylko ten zadziałał, tak wdzięczny, ale dlaczego? - Dimitrios Mistriotis
Podwójne uchwyty są "nowoczesnym" rozszerzeniem; np. nie będą robić podziału na słowa (na przykład dla nazw plików ze spacjami) i nadal będą pracować dla pustych łańcuchów: mywiki.wooledge.org/BashFAQ/031 - bw1024
według tldp.org/LDP/abs/html/fto.html -a jest identyczne w stosunku do -e. Został "przestarzały", a jego użycie jest odradzane. W każdym razie +1 za wzmiankę o sprawdzeniu uszkodzonego łącza symlink - Luca Borrione
@dimitrismistriotis two "[" jest niemobilnym rozszerzeniem zaimplementowanym (inaczej) przez zsh i bash; generalnie powinieneś tego unikać, jeśli to w ogóle możliwe. - Good Person
Głosowałem za tym PONIEWAŻ użyłem [[. Jest to szeroko stosowane rozszerzenie. Jeśli wiesz, że używasz basha, nie ma powodu, aby go nie używać. Jest znacznie mniej podatny na błędy niż [. - Michael Potter


Warto wspomnieć, że jeśli potrzebujesz wykonać jedno polecenie, możesz skracać

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

do

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

lub

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

80
2017-08-11 09:15



Dzięki! Potrzebował alternatywy, która nie używa [[]] - Jonathan


Wolę zrobić następującą jedno-liniową, w POSIX format zgodny z powłoką:

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

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

Dla kilku poleceń, tak jak w scenariuszu:

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

Kiedy zacząłem to robić, rzadko używam już w pełni wypisanej składni !!


57
2017-10-18 16:09



Przede wszystkim nieślubione odniesienia zmiennych są podatne na błędy. To powiedziawszy, gdzie się mówi każdy bash manpage, że [ lub test wbudowany będzie testować istnienie pliku argumentu domyślnie (w przeciwieństwie do -e)? Czy nie byłoby to niejednoznaczne? AFAIK (i AIUI sekcja "WYRAŻENIA WARUNKOWE") jedyną rzeczą, która jest testowana z twoim podejściem jest to, że argument nie jest pusty (lub niezdefiniowany), co w tym przypadku jest tautologią (niech $DIR = '' i $FILE = '', wtedy argument jest nadal '//'). - PointedEars
Dowód: ls /foo, wynik ls: cannot access /foo: No such file or directory. [ /foo ] && echo 42, wynik 42. GNU bash, wersja 4.2.37 (1) - wydanie (i486-pc-linux-gnu). - PointedEars
@PointedEars: Nie udało mi się określić -f opcja, w tej chwili napisałem tę odpowiedź. Oczywiście zawsze możesz użyć -e, jeśli nie jesteś pewien, że będzie to zwykły plik. Dodatkowo we wszystkich moich skryptach przytaczam te konstrukcje, musiałem to właśnie przedłożyć bez odpowiedniej weryfikacji. - TechZilla
ACK. Ale pewnie wiesz, że jednolinijka nie rozwiąże problemu, jeśli: [ $condition ] && if_true || if_false jest podatny na błędy. W każdym razie, znajduję [ ! -f "$file" ] && if_not_exists łatwiejsze do odczytania i zrozumienia niż [ -f "$file" ] || if_not_exists. - PointedEars


Aby przetestować istnienie pliku, parametrem może być dowolny z następujących parametrów:

-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

Wszystkie poniższe testy dotyczą zwykłych plików, katalogów i dowiązań symbolicznych:

-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

Przykładowy skrypt:

#!/bin/bash
FILE=$1

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

36
2017-12-19 12:47





Powinieneś uważać na bieganie test dla zmiennej niecytowanej, ponieważ może powodować nieoczekiwane wyniki:

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

Zaleca się zwykle, aby testowana zmienna była otoczona podwójnymi cudzysłowami:

#!/bin/sh
FILE=$1

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

28
2018-01-24 19:43



Zalecenie to mieć każdy zmienna otoczona podwójnymi cudzysłowami, chyba że wiesz dokładnie, że masz jeden z rzadkich przypadków, w których jest to niepotrzebne, lub jeden z rzadszych przypadków, gdy jest szkodliwy. (I nie, to nie jest jedna z nich.) - Uwe
Czy chciałbyś wyjaśnić, dlaczego nie używasz podwójnego cudzysłowu? W przeciwnym razie nie widzę użyteczności w komentarzu. - artdanil
Miałem na myśli: Nie jest to jeden z nielicznych przypadków, w których jest to niepotrzebne lub szkodliwe. Programista powłoki powinien się przyzwyczaić do zamknięcia (prawie) każdej zmiennej podwójnym cudzysłowem; ta zasada nie ogranicza się do [ ... ]. - Uwe
Zobacz też stackoverflow.com/questions/10067266/... - tripleee


Istnieją trzy różne sposoby, aby to zrobić:

  1. Neguj status wyjścia za pomocą bash (żadna inna odpowiedź tego nie powiedziała):

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

    Lub:

    ! [ -e "$file" ] && echo "file does not exist"
    
  2. Neguj test w komendzie testowej [ (tak przedstawia się większość odpowiedzi wcześniej):

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

    Lub:

    [ ! -e "$file" ] && echo "file does not exist"
    
  3. Ustaw wynik ujemny na wynik testu (|| zamiast &&):

    Tylko:

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

    To wygląda głupio (IMO), nie używaj go, chyba że twój kod musi być przenośny do powłoki Bourne'a (np /bin/sh systemu Solaris 10 lub wcześniejszego), który nie posiadał operatora negacji rurociągu (!):

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

18
2017-08-05 18:10



Każda różnica przenośności między ! [ i [ !? - Frozen Flame
The ! [  jest POSIX dla potoków powłoki 2.9.2 (dowolne polecenie)  Otherwise, the exit status shall be the logical NOT of the exit status of the last command i [ !   to POSIX do testu  ! expression True if expression is false. False if expression is true. Tak więc oba są POSIX-ami, a z mojego doświadczenia wynika, że ​​oba są szeroko wspierane.
@FrozenFlame, powłoka Bourne'a nie miała ! słowo kluczowe wprowadzone przez powłokę Korn. Może jednak w przypadku Solaris 10 i starszych prawdopodobnie nie spotkamy skorupy Bourne'a. - Stephane Chazelas