Czy przy próbie źródła pliku nie chcesz, aby błąd wskazywał, że plik nie istnieje, więc wiesz, co naprawić?
Na przykład nvm zaleca dodanie tego do twojego profilu / rc:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Z powyższym, jeśli nvm.sh
nie istnieje, pojawi się „cichy błąd”. Ale jeśli spróbujesz . "$NVM_DIR/nvm.sh"
, wynik będzie FILE_PATH: No such file or directory
.
shell-script
JBallin
źródło
źródło
HOME
.Odpowiedzi:
W powłokach POSIX
.
jest specjalnym wbudowanym narzędziem, więc jego awaria powoduje zamknięcie powłoki (w niektórych takich powłokachbash
robi się to tylko w trybie POSIX).To, co kwalifikuje się jako błąd, zależy od powłoki. Nie wszystkie z nich wychodzą po błędzie składni podczas analizowania pliku, ale większość kończy działanie, gdy nie można znaleźć lub otworzyć pliku źródłowego. Nie znam żadnego, który by się zakończył, gdyby ostatnie polecenie w pliku źródłowym zwróciło z niezerowym statusem wyjścia (chyba że
errexit
opcja jest oczywiście włączona).Tutaj robiąc:
Jest to przypadek, w którym chcesz pobrać plik, jeśli on tam jest, i nie rób tego, jeśli go nie ma (lub jest pusty tutaj
-s
).Oznacza to, że nie należy go uważać za błąd (błąd krytyczny w powłokach POSIX), jeśli pliku nie ma, plik ten jest uważany za plik opcjonalny.
Nadal byłby (krytyczny) błąd, gdyby plik nie był czytelny lub był katalogiem lub (w niektórych powłokach), jeśli wystąpił błąd składniowy podczas analizowania go, co byłoby prawdziwymi warunkami błędu, które należy zgłosić.
Niektórzy twierdzą, że istnieje warunek wyścigu. Ale jedyne co to oznacza, to że powłoka wyjdzie z błędem, jeśli plik zostanie usunięty pomiędzy
[
i.
, ale argumentuję, że uzasadnione jest uznanie za błąd, że ten ustalony plik ścieżki nagle zniknie, gdy skrypt jest bieganie.Z drugiej strony,
gdzie
command
¹ usuwa specjalny atrybut.
polecenia (aby nie opuścił powłoki po błędzie) nie działałby, ponieważ:.
to błędy, ale także błędy poleceń uruchamianych w pliku źródłowymInne typowe składnie (zobacz na przykład
grep -r /etc/default /etc/init*
w systemach Debian skrypty inicjujące, na które nie zostałysystemd
jeszcze przekonwertowane (gdzieEnvironmentFile=-/etc/default/service
zamiast tego określa się opcjonalny plik środowiska)):[ -e "$file" ] && . "$file"
Sprawdź plik, który tam jest, wciąż go źródłuj, jeśli jest pusty. Nadal błąd krytyczny, jeśli nie można go otworzyć (nawet jeśli już tam jest lub był). Możesz zobaczyć więcej wariantów, takich jak
[ -f "$file" ]
(istnieje i jest zwykłym plikiem),[ -r "$file" ]
(jest czytelny) lub ich kombinacje.[ ! -e "$file" ] || . "$file"
Nieco lepsza wersja. Wyjaśnia, że nieistniejący plik jest przypadkiem OK. Oznacza to również, że
$?
będzie odzwierciedlał status wyjścia ostatniego polecenia uruchomionego w$file
(w poprzednim przypadku, jeśli tak1
, nie wiesz, czy to dlatego,$file
że nie istniało, czy to polecenie nie powiodło się).command . "$file"
Spodziewaj się, że plik tam będzie, ale nie zamykaj go, jeśli nie można go zinterpretować.
[ ! -e "$file" ] || command . "$file"
Kombinacja powyższych: jest OK, jeśli pliku nie ma, a dla powłok POSIX nieudane otwarcie (lub parsowanie) pliku jest zgłaszane, ale nie jest krytyczne (co może być bardziej pożądane
~/.profile
).¹ Uwaga:
zsh
Jednak nie można tego używaćcommand
, chyba że wsh
emulacji; zwróć uwagę, że w powłoce Kornasource
jest tak naprawdę pseudonimemcommand .
, niespecjalnym wariantem.
źródło
.bash_profile
. Chyba lepiej, niż przepraszam, ale czy bash jest kiedykolwiek w trybie POSIX, kiedy.bash_profile
jest pozyskiwany?bash
gdy nie jest w trybie POSIX. Chcesz,[ -e /file ] && . /file
jeśli nie uważasz, że to błąd, gdy plik nie istnieje. Następnie spróbuj użyć źródła, jeśli nie można tego zrobić tutaj..
już zgłosi błąd (na stderr). A jeśli chodzi o to, aby nie uważać go za błąd, gdy plik nie istnieje, jest to niepoprawne (i nie jest to możliwe, ze statusu wyjścia stwierdzić, czy.
nie powiodło się, ponieważ plik nie istniał lub był nieczytelny lub był brak możliwości przetworzenia lub ostatnie polecenie nie powiodło się), o których tutaj mówię w tej odpowiedzi.Opiekun
nvm
odpowiedzi:Moja interpretacja (w połączeniu z doskonałym wyjaśnieniem Stéphane'a i komentarzem Kusalanandy):
To jest prostsze i bezpieczniejsze.
Chroni przed powłokami POSIX wychodzącymi podczas uruchamiania z powodu brakującego pliku (z różnych powodów). Osoby używające powłok innych niż POSIX (np. Bash) mogą usunąć warunek, jeśli wolą.
źródło
/etc
, oznacza to, że niektórzy użytkownicy mają ten plik, a niektórzy go nie mają. IMHO, odpowiedźnvm
opiekuna dotyczy tylko jednego aspektu.Jak zauważyli JBallin i Stéphane Chazelas , w powłokach POSIX pozyskanie pliku, który nie istnieje, spowodowałby niepowodzenie logowania.
Ale dodanie testu, aby sprawdzić, czy plik istnieje, a następnie próba jego uzyskania może spowodować coś, co nazywa się warunkiem wyścigu. Jeśli coś zmieni się
nvm.sh
pomiędzy[ -s nvm.sh ]
i. nvm.sh
, spowoduje dokładnie błąd, którego próbują zapobiec, aczkolwiek znacznie rzadziej.Ogólnie rzecz biorąc, sposobem na zapobieganie warunkom wyścigowym jest po prostu wypróbowanie tego, co chcesz zrobić, a następnie usunięcie błędu, jeśli się nie powiedzie, np.
Okazuje się, że to nie działa w powłokach POSIX, ponieważ, jak wyżej,
.
niepowodzenie spowoduje natychmiastowe zamknięcie powłoki, zanim będzie można uruchomić obsługę błędów.Moja odpowiedź dowodzi, że powłoki POSIX nie mają związku z tym pytaniem, ponieważ
.bash_profile
nigdy nie powinny działać w trybie POSIX. W każdym razie możemy po prostu zrobić powyższy kod.Aby być najbezpieczniejszym, możemy upewnić się, że tryb POSIX nie działa lub że tryb POSIX zostanie wyłączony przy użyciu techniki opisanej w /unix//a/383581/3169 .
Odpowiedź Stéphane'a zawiera kilka użytecznych sugestii dotyczących sposobu obsługi wszystkich powłok POSIX, co moim zdaniem było intencją autora nvm, ale było nieco inne niż pytanie zadane tutaj, dlatego mamy wiele możliwych podejść, w zależności od tego, jaki jest twój cel .
źródło