Polecenie wyświetlenia dowolnego komunikatu, jeśli istnieje określony plik

11

Czy istnieje polecenie wyświetlania komunikatu „Tak”, jeśli istnieje konkretny plik? Nie ma potrzeby udostępniania funkcjonalności, jeśli plik nie istnieje.

James
źródło

Odpowiedzi:

25

Użyj tej prostej linijki Bash:

if [ -e FILENAME ] ; then echo Yes ; fi

Do -eocenia czek na true, jeśli FILENAMEistnieje, nie wiem co to jest (plik, katalog, link, urządzenie, ...).

Jeśli chcesz tylko sprawdzać zwykłe pliki, użyj -fzamiast tego, jak powiedział @Arronical .

Bajt Dowódca
źródło
18
[ -e FILENAME ] && echo Yes
Zeb McCorkle,
@ZebMcCorkle Prawidłowo, to też działa. Możesz opublikować to jako osobną odpowiedź.
Bajt Dowódca
3
Jeśli FILENAMEjest zmiennym rozszerzeniem lub zawiera znaki specjalne, nie zapomnij go zacytować. np w skrypcie [ -e "$1" ] && echo Yes.
Peter Cordes,
@PeterCordes, jeśli używasz bash, możesz użyć [[i ]]zamiast cytować zmienną.
Holloway
1
@Holloway: tak, ale czasami trzeba pisać przenośne skrypty, które wymagają tylko POSIX sh. Właśnie dlatego podałem bezpieczną wersję tego zamiast głosować i poprawiać odpowiedź bash. Należy również pamiętać, że cytowanie rozszerzeń nie stanowi problemu [[ ]], zawsze cytowanie jest dobrym nawykiem dla początkujących, którzy nie pamiętają specjalnych zasad dotyczących [[ ]]operatora lub kontekstów arytmetycznych.
Peter Cordes,
10

Możesz użyć tego prostego skryptu:

#!/bin/bash

if [[ -f $1 ]]; then
    echo "Yes"
    exit 0
else
    exit 1
fi

Zapisz to jako file-exists.sh. Następnie w Terminalu wpisz chmod +x file-exists.sh.

Użyj go w następujący sposób: ./file-exists.sh FILEgdzie zamieniasz FILEna plik, który chcesz sprawdzić, na przykład:

./file-exists.sh file.txt

Jeśli file.txtistnieje, Yeszostanie wydrukowany na terminalu, a program zakończy pracę ze statusem 0 (sukces). Jeśli plik nie istnieje, nic nie zostanie wydrukowane, a program zakończy pracę ze statusem 1 (błąd).

Jeśli jesteś ciekawy, dlaczego zawarłem exitpolecenie, czytaj dalej ...


Co jest z exitpoleceniem?

exitpowoduje normalne zakończenie procesu. Oznacza to w zasadzie: zatrzymuje skrypt. Akceptuje opcjonalny (numeryczny) parametr, który będzie statusem wyjścia skryptu, który go wywołał.

Ten status wyjścia umożliwia innym skryptom korzystanie ze file-existsskryptu i jest sposobem na poznanie, czy plik istnieje, czy nie.

Prostym przykładem, który wykorzystuje to, jest ten skrypt (zapisz go jako file-exists-cli.sh):

#!/bin/bash

echo "Enter a filename and I will tell you if it exists or not: "
read FILE
# Run `file-exists.sh` but discard any output because we don't need it in this example
./file-exists.sh $FILE &>> /dev/null
# #? is a special variable that holds the exit status of the previous command
if [[ $? == 0 ]]; then
    echo "$FILE exists"
else
    echo "$FILE does not exist"
fi

Czy zwykły chmod +x file-exists-cli.sh, a następnie uruchomić go: ./file-exists-cli.sh. Zobaczysz coś takiego:

Plik istnieje ( exit 0):

➜  ~ ./file-exists-cli.sh 
Enter a filename and I will tell you if it exists or not: 
booleans.py
booleans.py exists

Plik nie istnieje ( exit 1):

➜  ~ ./file-exists-cli.sh
Enter a filename and I will tell you if it exists or not: 
asdf
asdf does not exist
grooveplex
źródło
2
Dobrze, ale powinieneś cytować odniesienia do zmiennych jak "$1". Jeśli ma w nim białe znaki, łamie się bez cudzysłowów i mogą się zdarzyć inne złe rzeczy.
Joe
9

W powłoce bash w wierszu poleceń.

if [[ -f /path/to/file ]]; then echo "Yes"; fi

Korzysta z operatora warunkowego bash -fi sprawdza, czy plik istnieje i czy jest zwykłym plikiem. Jeśli chcesz przetestować pliki, w tym katalogi i łącza, użyj -e.

To świetny zasób dla warunkowych bashów.

Arroniczny
źródło
1
Dlaczego podwójne szelki?
Bajt Dowódca
1
Nie jestem fanem testoryginalnego formatu, wiem, że to przesada, ale to mój zwyczaj.
Arronical
7
@ByteCommander: podwójne nawiasy klamrowe są po prostu lepsze niż pojedyncze nawiasy klamrowe. Są częścią składni powłoki (zamiast wywoływania [polecenia, które zwykle wywołuje funkcję wbudowaną). Korygują niespójności i głupie zachowania wersji z pojedynczym nawiasiem klamrowym. [Wbudowane pozostaje dla kompatybilności, ale nie widzę żadnego dobrego powodu, aby używać go w nowym kodzie bash. (Jeśli musisz pisać skrypty zgodne z POSIX, które mogą działać na starożytnych powłokach lub coś w tym stylu, to jest inne.)
Nick Matteo
@kundor: Większość jednak zgadza się, że uczciwość „ [zwykle nazywa się wbudowanym” jest wątpliwa. type -a [dla mnie lista „wbudowana powłoka”, a następnie „ /usr/bin/[.”
wchargin
1
@wchargin: Obawiam się, że nie rozumiem o co ci chodzi. Twoje typewyniki wydają się potwierdzać to, co powiedziałem, nie?
Nick Matteo,
5

Najkrótsze polecenie do robienia tego, co chcesz, to:

test -e FILENAME && echo Yes

test -esprawdzi, czy podana nazwa istnieje w systemie plików. (Możesz użyć, test -faby ograniczyć się tylko do zwykłych plików. Zobacz man testwięcej.)

Jeśli podany warunek ma wartość true, wówczas testzwraca pomyślny status wyjścia (w przeciwnym razie zwraca status błędu). Łączymy oba polecenia za pomocą &&, co oznacza „wykonaj następne polecenie, jeśli poprzednie polecenie zakończyło się powodzeniem”. Następne polecenie po prostu drukuje Yesna standardowym wyjściu; w przypadku interaktywnej powłoki na terminalu.

Pozwala to uniknąć dodatkowego materiału tekstowego ifinstrukcji, ale daje ten sam rezultat. Użycie &&(lub jego przeciwieństwo ||) do powiązania poleceń działa dobrze, gdy zaangażowane jest tylko jedno polecenie. Jeśli chcesz zrobić więcej niż wykonanie pojedynczego polecenia w odpowiedzi na status wyjścia pojedynczego polecenia, wówczas użycie ifskładni szybko staje się znacznie bardziej czytelne.

Jak już wskazano w innych odpowiedziach, odpowiednikiem ifstylu będzie:

if test -e FILENAME; then echo Yes; fi

lub alternatywnie:

if test -e FILENAME
then
    echo Yes
fi

Do tych celów [i testsą równoważne, z wyjątkiem tego, że [wymaga zakończenia ].

CVn
źródło
4

Aby skorygować tego typu pytanie, istnieje wiele sposobów, a oto inny: użyj findpolecenia z -execflagą. Ścieżkę do pliku można podzielić na dwie części, find /etcktóre ustawiają katalog i -name FILENAMEokreślają nazwę pliku (duh!). -maxdepthbędzie nadal findpracował /etctylko z katalogiem i nie będzie schodził do podkatalogów

adminx@L455D:~$ find /etc -maxdepth 1  -name passwd -exec printf "YES\n" \;
YES
adminx@L455D:~$ find /etc -maxdepth 1  -name passwd1 -exec printf "YES\n" \;
adminx@L455D:~$ 

Innym sposobem jest stat:

adminx@L455D:~$ stat /etc/passwd1 &>/dev/null && echo YES
adminx@L455D:~$ stat /etc/passwd &>/dev/null && echo YES
YES

I alternatywnie przez python:

>>> import os
>>> if os.stat('/etc/passwd'): 
...    print 'YES'
... 
YES
>>> if os.stat('/etc/passwd1'): 
...    print 'YES'
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: '/etc/passwd1'

Lub alternatywa dla krótkiej linii poleceń:

 python -c "from os.path import exists; print 'Yes' if exists('/etc/fstab') else '' "
Sergiy Kolodyazhnyy
źródło