Jak mogę zmusić mv (lub * symbol wieloznaczny) do przeniesienia ukrytych plików?

133

Migruję mój katalog domowy ze starego systemu do nowego, a utworzony przeze mnie archiwum zawiera wszystko, w tym ukryte pliki, takie jak .bashrc. Jednak gdy przenoszę zawartość rozpakowanego archiwum (które znajdują się w / tmp) do mojego nowego katalogu domowego, ukryte pliki nie kopiują się ( mv /tmp/home/rcook/* /home/rcook/). Jak mogę zmusić mv do ich przeniesienia?

Właściwie myślę, że problemem nie jest mv, ale globbing bash. Jeśli to zrobię:

mkdir a
mkdir b
touch a/.foo
touch a/bar
mv a/* b/
ls -a a/ b/

Widzę to:

a/:
.  ..  .foo

b/:
.  ..  bar

a/.foonie poruszył się. Jak mogę uzyskać * symbol wieloznaczny, aby znaleźć ukryte pliki?

Tak, przypuszczam, że mógłbym zdekompresować plik archiwum bezpośrednio do mojego katalogu domowego, ale plik archiwum dekompresuje się do home/rcook/...i chcę mieć pewność, że zastąpię nowy plik .bashrcitp. Starymi, dostosowanymi wersjami i wiem, jak znaleźć i przenieść ukryte pliki jest cenną umiejętnością. Propozycje?


Niektóre odpowiedzi sugerują zrobienie czegoś takiego mv src/.* dest/. Jednak wypróbowałem to w moich katalogach testowych i dostałem błędy. Począwszy od:

rcook$ ls -a a/ b/
a/:
.  ..  bar  .foo

b/:
.  ..
rcook$ mv a/.* b/
mv: cannot move 'a/.' to 'b/.': Device or resource busy
mv: cannot remove 'a/..': Is a directory
rcook$ ls -a a/ b/
a/:
.  ..  bar

b/:
.  ..  .foo

Co ja robię źle?

Randall Cook
źródło

Odpowiedzi:

146

Możesz to zrobić :

shopt -s dotglob
mv /tmp/home/rcook/* /home/rcook/

Możesz włożyć

shopt -s dotglob

W twojej ~/.bashrcjeśli ma to być domyślny.

Zobacz http://mywiki.wooledge.org/glob


Inne podejście do kopiowania plików kropek:

mv /tmp/home/rcook/.[!.]* /home/rcook/

Nie używaj ..*pasującego wzorca ..(wskaźnik do katalogu nadrzędnego). Jeśli istnieją pliki, których nazwa zaczyna się od dwóch kropek ( ..something), użyj również wzorca ..?*.

Gilles Quenot
źródło
Proszę sprawdzić dodatki, które umieściłem na dole mojego pytania. Dzięki.
Randall Cook
1
Nie ma nic złego .i ..są to katalogi specjalne: odpowiednio aktualny i macierzysty . To tylko ostrzeżenie. Lepsze shopt -s dotglobrozwiązanie
Gilles Quenot
W końcu wykonałem dwa ruchy: mv home/rcook/* /home/rcook/potem mv home/rcook/.* /home/rcook/. To załatwiło sprawę, choć żałuję, że nie skorzystałem z linku i najpierw przeczytałem o trybie dotglob. Oszczędziłoby mi to kroku. +1
Randall Cook
Więc drugie podejście wymaga użycia ścieżek bezwzględnych?
franzlorenzon
3
Jeśli używasz zsh, można skorzystać z Duogólniające kwalifikator lub w GLOB_DOTSopcji powłoki .
mgalgs
43

W twoich dodatkach masz błędy, ale kod nadal działa. Jedyną rzeczą do dodania jest to, że kazałeś mu tylko skopiować pliki kropkowe. Próbować:

mv src/* src/.* dst/

Nadal będziesz otrzymywać błędy dotyczące. i .. wpisy, co jest w porządku. Ale ruch powinien się powieść.

~/scratch [andrew] $ mv from/* from/.* to/
mv: cannot move from/.’ to to/.’: Device or resource busy
mv: cannot remove from/..’: Is a directory
~/scratch [andrew] $ ls -a from/ to/
from/:
.  ..

to/:
.  ..  test  .test
Andrew Schwartz
źródło
1
Dobre punkty, @AndrewSchwartz. Też podoba mi się to podejście. Myślę, że zasługuje na większe uznanie.
Randall Cook
Podoba mi się odpowiedź @Drake Clarris, ponieważ korzystam z Amazon AWS CodeBuild, a niezerowy kod zwrotny spowodował zatrzymanie mojej kompilacji. Skończyło się jednak przenoszeniem jednego .hiddenpliku, który miałem jawnie rozwiązać, aby rozwiązać mój problem.
HeyWatch
Jeśli niezerowy kod wyjścia jest problemem, możesz go pominąć, np. Dodając || :( ||oznacza to wykonanie polecenia false / error, :to polecenie noop). Ale to również tłumiłoby prawidłowe błędy, np. Folder docelowy nie istnieje. Nie mogę znaleźć bardziej eleganckiego sposobu mvna wykluczenie wpisów .i ... Ale duży plus dla mnie nad cp to nie zapisywanie nowych plików na dysku.
Andrew Schwartz
10

Jeśli jesteś ls -lw katalogu, zobaczysz .i ..wśród wymienionych plików. Myślę więc, że mv .* /destbierze pod uwagę te wskazówki. Próbować:

mv /tmp/home/rcook/{*,.[^.]*,..?*} /home/rcook/

spowoduje to zignorowanie bieżących i nadrzędnych wskaźników katalogu.

Dostaniesz błąd, jeśli którykolwiek z tych trzech wzorców *, [^.]*czy ..?*pasuje do żadnego pliku, więc należy uwzględnić tylko te, które pasują do siebie.

Azamat
źródło
Miły. Podobna odpowiedź na ten styl globowania znajduje się tutaj: superuser.com/a/784046/144977 . Dzięki za opublikowanie tego.
phyatt,
7

Mogę wymyślić dwa możliwe rozwiązania. Pierwszym z nich jest użycie cp zamiast opcji rekurencyjnej, kopiowanie bieżącego katalogu do miejsca docelowego.

cp -Rp . /desired/directory

następnie możesz usunąć pliki źródłowe z bieżącego katalogu

Alternatywnie, jeśli wiesz, że pliki są nazwane zdrowo (bez spacji, symboli wieloznacznych, znaków niedrukowalnych), możesz zrobić coś takiego:

mv $(ls -A) /desired/directory
Drake Clarris
źródło
4
Kopiuj, a następnie usuń różni się znacznie od przenoszenia, jeśli źródło i cel znajdują się w tym samym systemie plików. Przynajmniej uwzględnij opcję -pzachowania metadanych. Używanie lspowinno być ostatecznością, a tutaj są lepsze, prostsze sposoby.
Gilles
2

W systemie Linux nie ma tak naprawdę „ukrytych” plików. Pliki zaczynające się od kropki są domyślnie ukryte przed listą plików.

Aby skopiować pliki nawet za pomocą globu, musisz poprzedzić ten plik znakiem, .np. mv -u .* fooA potem .foozobaczysz, jak foo/.foopo przeniesieniu.

Opcja -u przenosi pliki tylko wtedy, gdy źródło jest nowsze lub brakuje miejsca docelowego. Albo można po prostu zignorować błędy o przeprowadzce .i ..jak są specjalne pliki i nie można przesuwać, ale daj się złapać w .*glob przez powłokę.

dobey
źródło
Proszę sprawdzić dodatki, które umieściłem na dole mojego pytania. Dzięki.
Randall Cook
0

Więc mamy:

a
|-- .foo
`-- bar

i:

b

Sporo czasu poświęciłem na znalezienie lepszego rozwiązania niż wszystkie odpowiedzi tutaj.

Potem zajęło mi 30 sekund na to polecenie:

$ mv --help

Potem znalazłem swoją miłość:

$ mv a/ b/ -T

Uwaga: Nawet nie rozumiem argumentu -T. Po prostu zrobił to, czego potrzebowałem. Tutaj jest napisane:

-T, --no-target-katalog traktuje DEST jako normalny plik

użytkownik433901
źródło
1
Jeśli pominiesz ukośniki, nie będziesz potrzebować -T. Tak czy inaczej, w zasadzie mówi to mv, aby przenieść sam katalog, zamiast przenosić wszystkie pliki z jego wnętrza.
thomasrutter
@ thomasrutter, czy przeniesienie samego katalogu nie jest tym samym, co zmiana jego nazwy?
Randall Cook
3
Tak, jeśli cel nadrzędny pozostaje taki sam, to zasadniczo zmienia jego nazwę. Jednak odnieść się do niego, to prawdopodobnie nie pomoże odpowiedzieć na oryginalne pytanie, co było o przenoszeniu plików wewnątrz katalogu do danej lokalizacji.
thomasrutter
0

W moim przypadku po prostu próbowałem mvznaleźć jeden ukryty plik, a oto rozwiązanie:

FILE=.myHiddenFile
mv "$FILE" dest/

Wyjaśnienie

Na początku próbowałem:

mv .myHiddenFile dest/

Ale nadal pojawiał się błąd:

mv: cannot stat '.myHiddenFile': No such file or directory

Mimo że ls -alpokazał, że plik dest/istnieje i istnieje.

Wydaje się, że powodem jest to, że powłoka interpretowała „.” w nazwie pliku, więc przenosząc go do zmiennej, unika interpretacji. Prawdopodobnie istnieją inne sposoby rozwiązania tego problemu, ale to nam wystarczyło.

Izajasza
źródło
-1

Jeśli chcesz skopiować pliki, w tym pliki ukryte, do bieżącego katalogu, w którym się znajdujesz.

cp -Rp source-directory/. .
Stóg
źródło
1
Jest to bardzo podobne do odpowiedzi Drake'a Clarrisa z 2013 roku. Czy masz coś jeszcze do dodania?
Randall Cook