Polecenie typu mv foo* ~/bar/
produkuje ten komunikat w stderr, jeśli nie ma pasujących plików foo*
.
mv: cannot stat `foo*': No such file or directory
Jednak w skrypcie, nad którym pracuję, ta sprawa byłaby całkowicie w porządku i chciałbym pominąć tę wiadomość w naszych dziennikach.
Czy jest jakiś fajny sposób, aby powiedzieć mv
cicho, nawet jeśli nic nie zostało poruszone?
mv foo* ~/bar/ 2> /dev/null
?mv
. :) Ale tak się stanie.mv
implementacje obsługują-q
opcję ich wyciszenia, ale nie jest to część specyfikacji POSIXmv
. Na przykładmv
w jądrach GNU nie ma takiej opcji.Odpowiedzi:
Szukasz tego?
źródło
set -e
(który powinien być użyty w każdym skrypcie powłoki) zawiedzie. możesz dodać a,|| true
aby wyłączyć sprawdzanie pojedynczego polecenia.set -e
nie powinno być używane w każdym skrypcie powłoki, w wielu przypadkach sprawia, że zarządzanie błędami jest jeszcze bardziej złożone niż bez niego.Właściwie nie sądzę, aby wyciszanie
mv
było dobrym podejściem (pamiętaj, że może zgłosić ci również inne rzeczy, które mogą być interesujące ... np. Brakujące~/bar
). Chcesz go wyciszyć tylko w przypadku, gdy wyrażenie glob nie zwróci wyników. W rzeczywistości raczej wcale go nie wykonuje.Nie wygląda zbyt atrakcyjnie i działa tylko w
bash
.LUB
tylko chyba jesteś w
bash
zenullglob
zbioru. Płacisz jednak trzykrotnie za powtórzenie wzoru globu.źródło
foo*
gdy jest on jedynym w bieżącym katalogu, który pasuje do globufoo*
. Można to obejść za pomocą wyrażenia globalnego, które nie pasuje dosłownie, trudne. Np[ 'fo[o]*' = "$(echo fo[o]*)" ] || mv fo[o]* ~/bar/
.find . -maxdepth 1 -name 'foo*' -type f -print0 | xargs -0r mv -t ~/bar/
- GNU
mv
ma ładną opcję „najpierw docelową” (-t
) ixargs
może pominąć uruchamianie polecenia, jeśli nie ma żadnych danych wejściowych (-r
). Używanie-print0
i-0
odpowiednio zapewnia, że nie będzie bałaganu, gdy nazwy plików zawierają spacje i inne „śmieszne” rzeczy.źródło
-maxdepth
,-print0
,-0
a-r
także rozszerzenia GNU (chociaż niektóre z nich znajdują się w innych implementacjach w dzisiejszych czasach).mv
.Ważne jest, aby zdać sobie sprawę, że tak naprawdę to powłoka rozszerza
foo*
ją na listę pasujących nazw plików, więc niewielemv
można zrobić.Problem polega na tym, że gdy glob nie pasuje, niektóre powłoki takie jak
bash
(i większość innych powłok podobnych do Bourne'a, to zachowanie błędne zostało wprowadzone przez powłokę Bourne'a pod koniec lat 70.) przekazują wzorzec dosłownie do polecenia.Więc tutaj, gdy
foo*
nie pasuje do żadnego pliku, zamiast przerywać polecenie (jak robią to wcześniejsze powłoki Bourne'a i kilka nowoczesnych powłok), powłoka przekazujefoo*
plik dosłownymv
, więc w zasadzie prosimv
o przeniesienie pliku o nazwiefoo*
.Ten plik nie istnieje. Gdyby tak było, rzeczywiście pasowałby do wzorca, więc
mv
zgłasza błąd. Gdybyfoo[xy]
zamiast tego wzorzec ,mv
mógł przypadkowo przenieść plik o nazwiefoo[xy]
zamiast plikówfoox
ifooy
.Teraz nawet w tych powłokach, które nie mają tego problemu (przed Bourne, csh, tcsh, fish, zsh, bash -O failglob), nadal pojawiał się błąd
mv foo* ~/bar
, ale tym razem przez powłokę.Jeśli chcesz uznać to za błąd, jeśli nie ma pasującego pliku,
foo*
a w takim przypadku nie przenosić niczego, najpierw musisz zbudować listę plików (w sposób, który nie powoduje błędu, jak przy użyciunullglob
opcji niektóre muszle), a następnie tylko wywołaniemv
jest takie, że lista nie jest pusta.Byłoby to lepsze niż ukrywanie wszystkich błędów
mv
(tak jak w przypadku dodawania2> /dev/null
), jak gdybymv
nie powiodło się z jakiegokolwiek innego powodu, prawdopodobnie nadal chcesz wiedzieć, dlaczego.w Zsh
Lub użyj funkcji anonimowej, aby uniknąć używania zmiennej tymczasowej:
zsh
jest jedną z tych powłok, które nie zawierają błędu Bourne'a i zgłaszają błąd bez wykonania polecenia, gdy glob nie pasuje (anullglob
opcja nie została włączona), więc tutaj możesz ukryćzsh
błąd i przywrócić stderr dla,mv
więc nadal będziesz widziećmv
błędy, jeśli takie istnieją, ale nie błąd dotyczący niepasujących globów:Lub możesz użyć tego,
zargs
co uniknęłoby również problemów, gdybyfoo*
glob rozszerzył się do zbyt dużych plików.W ksh93:
W bash:
bash
nie ma składni, aby włączyć tylkonullglob
dla jednego globu, afailglob
opcja anuluje,nullglob
więc potrzebujesz takich rzeczy jak:lub ustaw opcje w podpowłoce, aby zapisać trzeba je wcześniej zapisać, a następnie przywrócić.
W
yash
W
fish
W skorupce ryby zachowanie nullglob jest domyślnym
set
poleceniem, więc jest to po prostu:POSIXly
W
nullglob
POSIXsh
nie ma opcji ani tablicy innej niż parametry pozycyjne. Istnieje jednak sztuczka, której można użyć do wykrycia, czy glob pasuje, czy nie:Używając zarówno a, jak
foo[*]
ifoo*
glob, możemy rozróżnić przypadek, w którym nie ma pasującego pliku, i ten, w którym jest jeden plik, który jest wywoływanyfoo*
(czegoset -- foo*
nie można zrobić).Więcej lektur:
źródło
Prawdopodobnie nie jest to najlepsze, ale możesz użyć
find
polecenia, aby sprawdzić, czy folder jest pusty, czy nie:źródło
foo*
ścieżkę wyszukiwania dofind
.Zakładam, że używasz bash, ponieważ ten błąd zależy od zachowania bash, aby rozwinąć do siebie niedopasowane globusy. (Dla porównania, zsh zgłasza błąd przy próbie rozwinięcia niedopasowanego globu.)
A co z następującym obejściem?
To po cichu zignoruje błąd
mv
ifls -d foo*
, a nadal będzie rejestrować błędy, jeśli sięls foo*
powiedzie, ale sięmv
nie powiedzie. (Uwaga,ls foo*
może się nie powieść z innych przyczyn niżfoo*
nieistniejących, np. Niewystarczających uprawnień, problemów z FS itp., Więc takie rozwiązanie zostanie po cichu zignorowane).źródło
bash
). +1 za wzięcie pod uwagę faktu, żemv
może się nie powieść z innych powodów niżfoo*
nieistniejący.ls
ls -d foo*
może powrócić z niezerowym statusem wyjścia również z innych powodów, na przykład poln -s /nowhere foobar
(przynajmniej w niektórychls
implementacjach).Możesz zrobić na przykład
mv 1>/dev/null 2>&1 foo* ~/bar/
lubmv foo* ~/bar/ 1&>2
Aby uzyskać więcej informacji, zobacz: http://mywiki.wooledge.org/BashFAQ/055
źródło
mv foo* ~/bar/ 1&>2
nie wycisza polecenia, wysyła to, co byłoby na stdout, aby było również na stderr./dev/null
zNUL
1
i co2
znaczy?Możesz oszukiwać (przenośnie) za pomocą
perl
:źródło
Jeśli zamierzasz używać Perla, równie dobrze możesz przejść całą drogę:
lub jako jedna linijka:
(Szczegółowe informacje na temat
move
polecenia znajdują się w dokumentacji File :: Copy .)źródło
Zamiast
możesz to zrobić
Prosty, czytelny :)
źródło
cp
nierm
milczą, jeślifoo*
nie istnieje.Niezależnie od tego, czy powyższe polecenie zakończyło się powodzeniem, czy nie, możemy sprawdzić status wyjścia poprzedniego polecenia
jeśli wyjście echa $? jest inny niż 0 oznacza, że polecenie nie powiodło się, jeśli wyjście ma wartość 0, oznacza, że polecenie zakończyło się pomyślnie
źródło