Ostatnio byłem zaskoczony, gdy zrobiłem coś podobnego
mv ./* ../somedirectory
i stwierdziłem, że podobne pliki .gitignore
nie zostały przeniesione.
Większość pracy wykonuję w Zsh na OS X, a ta niespodzianka ugryzła mnie w bicie na CentOS. Próbowałem bash na OS X i znalazłem to samo zachowanie: *
nie pasuje do plików kropek. Wydaje mi się to bardzo niepożądane, ale najwyraźniej jest to domyślne ustawienie bash. (To może być domyślna wartość zsh dla wszystkich, które pamiętam, ale mogłem ją zmienić wiele lat temu w moim .zshrc i zapomniałem, że kiedykolwiek działał inaczej.)
Jak mogę skonfigurować bash, aby zachowywał się tak, jak się spodziewałem: aby * pasował do wszystkich plików i nie ignorował plików kropek.
W przypadku, gdy jest to w ogóle niejasne, oto jak go odtworzyć
cd /tmp
mkdir {t,d}est
touch test/{.,}{1,2,3,4,5,6,7}
ls -hal test
mv test/* dest
ls -hal test # notice dot files are still there
ls -hal dest # notice only some files were mv'ed
Odpowiedzi:
Grzmotnąć
Jak już zauważyłeś, bash nie będzie pasował do
.
znaku na początku nazwy lub ukośnika. Aby zmienić dopasowanie kropki, musisz ustawićdotglob
opcję - man bash :Aby włączyć / ustawić za pomocą bash
shopt
, np .:W przypadku zsh możesz również użyć tej
dotglob
opcji, ale będziesz musiał użyćsetopt
jej, np .:źródło
zsh
, lepszym rozwiązaniem jest włączenie dotglob dla poszczególnychmv test/*(D) /dest
Testowałem to i to rozwiązuje problem:
Wynik:
źródło
*
to glob rozwinięty przez powłokę. Domyślnie powłoki nie zawierają plików, których nazwa zaczyna się od.
(zwanych plikami ukrytymi lub plikami dotfiles), chyba że wiodące hasło.
jest wprowadzone dosłownie.*
lub[.]*
lub?*
lub*.*
lubdir/*
nie będzie zawierać plików kropkowych..*
lubdir/.*
będzie.Więc możesz zrobić:
jednak niektóre powłoki, w tym
bash
(ale niezsh
,mksh
ani niefish
), mają tę wadę, że rozszerzenie.*
zawiera.
i..
specjalne pozycje katalogu, których tu nie chcesz (i generalnie nigdy nie chcesz, aby glob zawierał, dlatego nazywam to błędem).Z tego powodu okaże się, że czasami ludzie używają (w powłokach podobnych do Bourne'a):
To trzy globusy, pierwszy pasujący do nie ukrytych plików, drugi z nazwami plików rozpoczynającymi się od,
.
po którym następuje znak inny niż,.
a trzeci z nazwami plików rozpoczynającymi się od,..
po którym następuje co najmniej jeden znak.Jednak niektóre nowoczesne muszle mają na to lepsze sposoby
zsh
Za
zsh
pomocą(D)
kwalifikatora glob można określić, że glob powinien zawierać pliki kropkowe:zsh
naprawiono również tę inną wadę powłoki Bourne'a, ponieważ jeśli wzorzec nie pasuje,mv
polecenie nie jest uruchamiane.Jak powiedziano powyżej, nigdy też nie będzie zawierać
.
ani..
w swoich globach, więcbędzie bezpieczny. Jeśli jednak nie ma pasującego pliku
*
lub żaden plik nie pasuje,.*
polecenie zostanie przerwane, więc lepiej użyć:Podobnie jak w niektórych innych powłokach, możesz również zmusić wszystkie globusy do dołączania plików dot (na przykład, jeśli chcesz, aby pliki dot były dołączane częściej niż nie):
lub:
Następnie, jeśli chcesz, aby określony glob nie zawierał plików dot, możesz go napisać:
Lub:
Grzmotnąć
Niestety
bash
nie ma globalnych kwalifikatorów. Pozostaje Ci zatem włączenie globalnego dodawania plików. Wbash
składni jest:(i używać
[^.]*
do globów bez ukrytych plików).Z
dotglob
,bash
nie obejmuje.
ani..
w globs takich jak*
, ale nadal robi to dla takich globów.*
.Jeśli ustawisz
GLOBIGNORE
zmienną na coś niepustego, wówczas automatycznie włączadotglob
opcję i wyklucza.
i..
z.*
globusów, ale nie z globusówdir/.*
lub.*/file
jedynek (!), Dzięki czemu zabezpieczenie jest całkiem bezużyteczne. Mógłbyś zrobić,GLOBIGNORE='*/.:*/..:./*:../*:*/./*:*/../*'
ale wtedy zniszczyłoby globusy takie jak*/.
lub./*
lub../*
.Lepszym obejściem jest użycie
[.]*
lubdir/[.]*
lub[.]*/file
(zdotglob
włączonym) do rozwijania plików dot, z wyjątkiem.
i..
.ryba
fish
globusy nie obejmują.
ani..
. Gdy nie ma dopasowania, w zależności od wersji, będzie działać jakzsh
(lubbash -o failglob
) lubbash -o nullglob
.Działa, jeśli istnieją zarówno pliki ukryte, jak i nie ukryte. W przeciwnym razie YMMV i w niektórych wersjach może wywoływać,
mv -- /dest
jeśli w ogóle nie ma pliku.ksh93
W
ksh93
żadnym z nich nie ma kwalifikatora glob . Możesz dołączać pliki kropkowe do globów za pomocą:W przeciwieństwie do
bash
tychGLOBIGNORE
, jest to zrobione poprawnie, a także rozwiązuje problem.*
włączenia.
i..
.yash
yash
posiadadot-glob
opcję (set -o dot-glob
), ale wbrew temubash
, ekspansje glob (nawet z*
) to.
i..
tak jest całkiem bezużyteczny.tcsh
Działa jak w
bash
, to jest*
to kropka pliki wyjątkiem.
a..
jednak.*
wciąż zawiera.
i..
(i można użyć[.]*
, aby rozwinąć ukryte pliki z wyjątkiem.
i..
).źródło
Najprostszym sposobem na wydrukowanie pasujących plików kropek w bash jest ignorowanie
.
i..
:Testować:
Wydrukował wszystkie pliki z kropkami lub nie, z godnym uwagi wyjątkiem
.
i..
.Twój przykład będzie również działał poprawnie:
Brak ważnych plików.
Pliki systemowe
.
..
nadal istnieją, ale rozszerzenie powłoki (używając *) ich nie uwzględni.A docelowy katalog usuwające zawiera wszystkie pliki:
Dlaczego?
To działa, ponieważ ustawienie GLOBIGNORE ma to niepożądane efekty:
shopt -s dotglob
) na matematyczne pliki kropek przy rozszerzeniach..
i..
są ignorowane, gdy jest ustawiony GLOBIGNORE, a nie jest pusty.Szczegóły w instrukcji:
LESS=+'/The GLOBIGNORE' man bash
.Musimy także ustawić zmienną GLOBIGNORE tak, aby zawierała nazwę, której żadna nazwa pliku nie mogłaby się równać:
ukośnik (i coś innego tylko jako podwójne zabezpieczenie).
Przydatne może być również ustawienie nullglob, jeśli jest to konieczne, aby uniknąć sytuacji,
*
gdy nie ma pliku pasującego do*
.źródło
Bardzo interesuje to ustawienie GLOBIGNORE = / + / @ user79743
Z mojego doświadczenia wynika, że rozbrajanie dotglob jest złym biznesem dla prawie wszystkich twoich poleceń (cp, mv itp.) ALE to samo dotyczy ustawiania nullglob (szczególnie z wyrażeniami regularnymi, które następnie wymagają ucieczki!).
Niemniej jednak, jeśli musisz je ustawić na początku programu, ale ingerujesz w określone części, w których wywołujesz polecenia takie jak cp, mv itp. Lub używasz wyrażeń regularnych, po prostu zrób to:
źródło