Pisałem kilka scenariuszy i napisałem coś podobnego
ARTIFACTS="/SOME/PATH"
[ -d $ARTIFCATS ] && rm -rf $ARTIFACTS/*
Stało się tak, że z głupoty wykonałem drugą linię bez wykonania pierwszej. Okazało się, że [-d ""] zwraca true, a wyrażenie się stało
rm -rf /*
Na szczęście była to tylko maszyna testowa i nie byłem sudo, ale straciłem trochę danych
Moje pytanie brzmi: dlaczego [-d ""] zwraca true ?? dokumentacja wyraźnie stwierdza, że sprawdza, czy ścieżka istnieje i czy jest folderem
Rozwiązałem problem za pomocą
[ -e $ARTIFACTS ]
który wydaje się działać
Twoje zdrowie
rm -rf $ARTIFACTS
bez/*
. Spowoduje to również usunięcie$ARTIFACTS
katalogu, co jest w porządku, ponieważ jeśli chcę mieć pewność, że istnieje przed włożeniem czegoś do niego, imkdir -p $ARTIFACTS
tak wykonam . Usunie również ukryte pliki w środku$ARTIFACTS
, co również jest w porządku, ponieważ nie pisałbym,rm -rf $ARTIFACTS/*
gdyby$ARTIFACTS
zawierał coś, co chciałem zapisać.Odpowiedzi:
1. Te dwa testy zwracają wartość true :
zgodnie z POSIX (jak wyjaśniono @Tim).
2. Ale ta powraca fałszywa ( nie prawda, jak wskazano w pytaniu)
ponieważ
test
jest wywoływany z dwoma argumentami (chociaż drugi jest pustym ciągiem).3. Dlatego dobrą praktyką jest używanie
[[ … ]]
zamiasttest
([ … ]
), które zapewnia większość (wszystkich?) Obecnych powłok. Ta konstrukcja sprawdza, czy podasz wystarczającą liczbę argumentów (w przeciwnym razie generuje błąd i przerywa)lub po prostu zachowuje się tak, jak można się spodziewać:
4. I, jak wskazał @Gilles, jeszcze ważniejsze jest podwójne cytowanie podstawień. Więc
-d "$SOME_UNSET_VAR"
rozwija się-d ""
i zwraca false nawet przytest
(równa się przypadkowi 2). Dlatego jest to również zgodne z powłoką Bourne'ash
:testowane przy użyciu bash 3.00.16 (1) i 4.1.5 (1)
źródło
[[ … ]]
ale nie zwykłysh
. Naprawdę ważne praktyką jest umieścić w cudzysłowie podstawień komend :[ -d "$ARTIFACTS" ]
.Ta kwestia została już odpowiedział na StackOverflow. Mówi, że zgodnie ze standardem POSIX
test
powinien zawsze zwracać sukces, jeśli jest wywoływany z dokładnie jednym niepustym argumentem (i bez innych argumentów).Tak też powinno być w przypadku
test -e
(i tak naprawdę jest w moim systemie), więc bądź ostrożny.Zamiast tego użyj:
test
zostanie następnie wywołany z dwoma argumentami, nawet jeśli zmienna jest pusta i w tym przypadku zwróci false.źródło
[ ! -z $ARTIFACTS ] && [ -d $ARTIFACTS ]
nie jest lepszy: obsługuje tylko konkretny przypadek, gdy$ARTIFACTS
jest pusty, ale zawodzi, gdy$ARTIFACTS
może zawierać białe znaki lub\[?*
.[ -d "$ARTIFACTS" ]
jest właściwym sposobem na zrobienie tego (lub[[ -d $ARTIFACTS ]]
w powłokach, które mają[[ … ]]
).Jesteś zły . Działa, ponieważ
$ARTIFACTS
jest teraz ustawiony na coś.Gdy zmienna nie jest ustawiona, wtedy powiedz
lub
będzie zarówno ocenia się
true
, ponieważ implikuje mówiąci
odpowiednio. (Mówienie
[ foobar ]
zawsze ocenia się jako prawdziwe).Powiedzenie
przydaje się w takich sytuacjach.
help set
powiedziałbym ci:źródło
Sprawdź, czy ustawiłeś zmienną ARTIFACTS i sprawdzałeś ARTIFCATS. Prawdopodobnie źle wpisujesz?
W każdym razie, -d oraz -e dawałyby takie same wyniki dla zmiennych nieustawionych.
Dlatego używaj podwójnych cudzysłowów, a to ci pomoże.
UWAGA: Jeśli twój „/ SOME / PATH” ma jakiś folder ze spacją, skrypt, o którym wspomniałeś, zepsuje się z błędem „oczekiwany operator binarny”.
Przykład:
da sobie radę. Nie zapomnij również wstawić cytatów w
rm
wywołaniu (rm -rf $ARTIFACTS
chętnie usunę,/home
a następnie narzekasz nabackup/*
nieistnienie).Również włączenie
-L
sprawdzania sprawi, że będzie to katalog, a nie tylko symboliczne łącze do katalogu.Zasadniczo
źródło