Jak przenosić wszystkie pliki (w tym ukryte) z jednego katalogu do drugiego?

132

Jak przenieść wszystkie pliki z katalogu (w tym te ukryte) do innego katalogu?

Na przykład, jeśli mam folder „Foo” z plikami „.hidden” i „notHidden”, jak przenieść oba pliki do katalogu o nazwie „Bar”? Poniższe nie działa, ponieważ plik „.hidden” pozostaje w „Foo”.

mv Foo/* Bar/

Spróbuj sam.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
Cory Klein
źródło
Bah, wiedziałem, że powinienem odświeżyć odpowiedzi przed wpisaniem mojego. Bardzo pomocny link.
Steven D
Niestety, pytanie to się tutaj skończyło, ponieważ powiedziałem na SO, że powinien się tu przenieść lub SU, więc oczywiście przeniósł się tutaj, gdy był już duplikat SU :)
Michael Mrozek
Osobiście uważam, że * specyficzne pytania i odpowiedzi powinny być nie na temat SU. Przy obecnych zasadach kończy się mnóstwo kolizji treści między nimi - jak to pytanie.
Cory Klein

Odpowiedzi:

151

Zsh

mv Foo/*(DN) Bar/

lub

setopt -s glob_dots
mv Foo/*(N) Bar/

(Pomiń, (N)jeśli wiesz, że katalog nie jest pusty).

Grzmotnąć

shopt -s dotglob nullglob
mv Foo/* Bar/

Ksh93

Jeśli wiesz, że katalog nie jest pusty:

FIGNORE='.?(.)'
mv Foo/* Bar/

Standardowy (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

Jeśli chcesz, aby mvpolecenie zwróciło status błędu, nawet jeśli się powiodło, jest to o wiele prostsze:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find i GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

Znalezienie standardowe

Jeśli nie przeszkadza ci przejście do katalogu źródłowego:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune

Oto więcej szczegółów na temat kontrolowania, czy pliki kropek są dopasowane w bash, ksh93 i zsh.

Grzmotnąć

Ustaw dotglobopcję .

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

Istnieje również bardziej elastyczna GLOBIGNOREzmienna , którą można ustawić na listę wzorców symboli wieloznacznych oddzielonych dwukropkami, które mają być ignorowane. Jeśli nie jest ustawiony (ustawienie domyślne), powłoka zachowuje się tak, jakby wartość była pusta, jeśli dotglobjest ustawiona, i tak, jakby wartość była, .*jeśli opcja była nieaktywna. Zobacz Rozszerzenie nazwy pliku w instrukcji. Wszechobecna katalogów .i ..zawsze są pominięte, chyba że .jest dopasowany dosłownie przez wzorzec.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Ksh93

Ustaw FIGNOREzmienną . Jeśli nieustawione (ustawienie domyślne), powłoka zachowuje się tak, jakby była to wartość .*. Aby zignorować .i .., należy je jednoznacznie dopasować (instrukcja w ksh 93s + 2008-01-31 stwierdza, że .i ..zawsze są ignorowane, ale nie opisuje to poprawnie faktycznego zachowania).

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero

Możesz dodać pliki kropek do wzorca , dopasowując je jawnie.

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

Aby rozszerzenie było puste, jeśli katalog jest pusty, użyj Nopcji dopasowania wzorca: ~(N)@(*|.[^.]*|..?*)lub ~(N:*|.[^.]*|..?*).

Zsh

Ustaw dot_globopcję .

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

.i ..nigdy nie są dopasowywane, nawet jeśli wzorzec .wyraźnie pasuje do wiodącego .

% echo .*
..two .one

Możesz dołączyć pliki kropek według określonego wzorca z D kwalifikatorem glob .

% echo *(D)
..two .one none zero

Dodaj Nkwalifikator glob aby ekspansję wyjdzie pusty w pustym katalogu: *(DN).


Uwaga: można uzyskać nazwy pliku wyników dylatacyjnych w różnych zleceń (np nonenastępnie .onenastępuje ..two) w oparciu o ustawieniach tych LC_COLLATE, LC_ALLoraz LANGzmiennych.

Gilles
źródło
1
Dlaczego nullglob? Bardziej sensowne byłoby przerwanie mvpolecenia (jak fish, csh / tcsh, zsh (bez (N)) do lub bash z failglob) niż uruchomienie mv /Bar/polecenia, które nie ma sensu.
Stéphane Chazelas
1
Powiedziałbym, że twój opis GLOBIGNORE jest niedokładny i wprowadzający w błąd. Ustawianie GLOBIGNORE do niepustym wartości włącza dotglob i sprawia, że .i ..nigdy nie są dopasowane (podobnie jak w innych sensownych muszli jak zsh, ryby, pdksh i pochodnych), nawet jeśli włączyć dotglob wycofać później. ( GLOBIGNORE=:; shopt -u dotglob; echo .*nie wyjdzie .i ..). Ustawienie GLOBIGNORE do .:..lub .czy :mają taki sam efekt.
Stéphane Chazelas
ksh93zawsze ignoruje .i ..wydaje się, że został złamany pomiędzy ksh93k+(gdzie działał) a ksh93m(gdzie już nie działa). Zauważ, że jest źle, ksh93ponieważ pobiera wartość FIGNORE ze środowiska, więc FIGNORE='!(..)'na przykład env var może wywołać spustoszenie.
Stéphane Chazelas
24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

Od man bash

dotglob Jeśli ustawione, bash zawiera nazwy plików rozpoczynające się od „.” w wynikach rozwinięcia nazwy ścieżki.

SiegeX
źródło
Z zastrzeżeniem, że to polecenie zwraca kod błędu, jeśli katalog był pusty (mimo że polecenie faktycznie wykonało się zgodnie z przeznaczeniem).
Gilles
1
@Gilles, błąd będzie wynikał z mvnarzekania, że ​​ten plik o nazwie Foo/*nie istnieje. Co ciekawe, jeśli Foomożna przeszukiwać, ale nie można go odczytać, a tam jest wywołany plik, *nie pojawi się błąd, ten plik zostanie przeniesiony, ale nie pozostałe w katalogu. bashposiada failglobopcję tak zachowuje się bardziej jak zsh, fishlub csh/ tcshi przerwać polecenie z błędem gdy glob nie może być rozszerzona zamiast tego fałszywego zachowania pozostawiając glob jak jest.
Stéphane Chazelas
7

Prostym sposobem na to bashjest

mv {Foo/*,Foo/.*} Bar/

Ale spowoduje to także przeniesienie katalogów.

Jeśli chcesz przenieść wszystkie pliki, w tym ukryte, ale nie chcesz przenosić żadnego katalogu, możesz użyć pętli for i przetestować.

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;

Miesiąc Borysa
źródło
4

Jednym ze sposobów jest użycie find:

find Foo/ -type f -exec mv -t Bar/ {} \+

-type fOgranicza polecenie Znajdź, aby znaleźć pliki. Należy przeprowadzać dochodzenia w sprawie -type, -maxdepth, i -mindepthopcje find, aby dostosować polecenia uwagę podkatalogów. Znajdź ma długą, ale bardzo pomocną stronę podręcznika .

Steven D.
źródło
3
To przenosi tylko zwykłe pliki Foo/, a nie podkatalogi i inne pliki.
Gilles
2

Spróbuj wykonać polecenie kopiowania cp:

$ cp -r myfolder/* destinationfolder

cp -r oznacza kopiowanie rekurencyjne, więc wszystkie foldery i pliki zostaną skopiowane.

Możesz użyć polecenia rmremove, aby usunąć folder:

$ rm -r myfolder

Zobacz więcej: przenieś wszystkie pliki z katalogu do innego .

ucefkh
źródło
2
Nie najlepiej, gdy przenosisz dużo dużych plików, ale myślę, że to zadziała.
Cory Klein
Może jeśli użyjesz kropki zamiast gwiazdy?
vincent
1

Rsync to kolejna opcja:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

Działa to, ponieważ w rsync ukośnik końcowy ma znaczenie, sourcedirectory/odnosi się do zawartości katalogu, podczas gdy sourcedirectoryodnosi się do samego katalogu.

Wadą tej metody jest to, że rsync wyczyści pliki dopiero po przeniesieniu, a nie katalog. Pozostaje ci więc puste drzewo katalogów. Aby obejść ten problem, zobacz:

Przenosić pliki i usuwać katalogi za pomocą rsync?

Chociaż może to nie być optymalne dla operacji przenoszenia, może być niezwykle przydatne w przypadku operacji kopiowania.

Grumbel
źródło
1

Odpowiedz na bash / fish

Oto sposób na zrobienie tego za pomocą symboli wieloznacznych:

.[!.]* ..?*dopasuje wszystkie ukryte pliki oprócz .i..

.[!.]* ..?* *dopasuje wszystkie pliki (ukryte lub nie) oprócz .i..

Aby odpowiedzieć na konkretny przykład tego pytania, potrzebujesz cd foo && mv .[!.]* ..?* * ../bar

Wyjaśnienie

.[!.]*dopasowuje nazwy plików zaczynające się od jednej kropki, po której następuje dowolny znak oprócz kropki, po której opcjonalnie następuje dowolny ciąg. Jest to wystarczająco blisko, ale brakuje plików zaczynających się od dwóch kropek, takich jak ..foo. Aby dołączyć takie pliki, dodajemy ..?*pasujące nazwy plików zaczynające się od dwóch kropek, po których następuje dowolny znak, opcjonalnie po nim dowolny ciąg.

Test

Możesz przetestować te symbole wieloznaczne za pomocą poniższych poleceń. Próbowałem z powodzeniem pod batem i rybą. Zawodzą pod sh, zsh, xonsh.

mkdir temp
cd temp
touch  a  .b  .bc  ..c  ..cd  ...d  ...de
ls .[!.]* ..?*
# you get this output:
          .b  .bc  ..c  ..cd  ...d  ...de
# cleanup
cd ..
rm -rf temp
ndemou
źródło
0

Możesz także znaleźć i grep z cudzysłowami wstecznymi, aby wybrać pliki dla polecenia przenoszenia. Przekaż je do mv.

To znaczy dla ukrytych plików

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

Więc

mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar

Przenosi tylko wybrane ukryte pliki do Bar:

mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar

Przenosi wszystkie pliki w Foo do Baru od „.” w poleceniu egrep działa jak symbol wieloznaczny bez nawiasów kwadratowych.

^Charakter zapewnia rozpoczyna mecz od początku linii.

Niektóre szczegóły egrepdopasowania wzoru można znaleźć tutaj .

Korzystanie z maxdepth 1zatrzymania wyszukiwania przed przejściem do podkatalogów.

użytkownik3192145
źródło
0

Inspirowany tą odpowiedzią :

Bez kopiowania plików ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Ostrzeżenia:

  • --link-destścieżka musi być bezwzględna lub względna w stosunku do DESTINATION ( Bar w przykładzie)

  • Musisz wstawić /po ŹRÓDŁO ( Foo/w przykładzie), w przeciwnym razie skopiuje folder SOURCE zamiast jego zawartości.

palindrom
źródło
0

Uważam, że działa to dobrze w przypadku bash i nie trzeba zmieniać opcji powłoki

mv sourcedir/{*,.[^.]*} destdir/

EDYTOWAĆ:

Tak więc, jak stwierdził G-man, moja pierwotna odpowiedź nie jest zgodna z posixem i jest prawie taka sama jak powyższa odpowiedź ndemou z jedną zmianą, która polega na użyciu rozwijania nawiasów klamrowych do tworzenia list ciągów znaków, które są następnie przetwarzane. Oznacza to po prostu, że nie musisz cdwchodzić do katalogu źródłowego. Naprawdę niezbyt duża zmiana, ale jest inna.

przykład: załóżmy, że masz już następujący układ.

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

W pierwotnym pytaniu wspomniano tylko o ukrytych plikach z pojedynczą kropką, ale powiedzmy, że niektóre mają dwa lub więcej kropek na początku nazwy. Możesz po prostu dodać dodatkowe wyrażenie do nawiasów klamrowych. Następnie możemy wykonać

mv sourcedir/{*,.[!.]*,..?*} destdir/

Zostanie to rozszerzone do następującego:

mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/

Powinieneś teraz zobaczyć wszystkie pliki znajdujące się w destdir :

 $ tree -a
.
├── destdir
   ├── ..d1
   ├── ..d2
   ├── ..double
   ├── file-1
   ├── file-2
   ├── .hidden-1
   ├── .hidden-2
   ├── ...t1
   └── ...t2
└── sourcedir

Możesz robić całkiem fajne rzeczy z szelkami w bashu z jeszcze większą liczbą dodatków w 4.x. Sprawdź bash-hakerów, aby uzyskać jakieś fajne przykłady.

cmndr sp0ck
źródło
1
To w zasadzie powiela odpowiedź ndemou, z wyjątkiem dodania nawiasów klamrowych (bez ich wyjaśniania). Ale (1) twoja odpowiedź nie pasuje do plików, których nazwy zaczynają się od .., i (2) aby być zgodnym z POSIX , powinieneś użyć !zamiast ^; tj  {*,.[!.]*}.
G-Man
@ G-Man, przepraszam za to. Więc masz rację i moje złe, że nie widziałeś odpowiedzi ndemou. Są prawie takie same. 1. dziękuję za wskazanie, że moja wersja nie jest zgodna z posix. 2. Używam rozszerzenia nawiasu klamrowego do tworzenia list ciągów, które następnie powłoka użyje do wykonania akcji. Oznacza to również, że nie muszę cdwchodzić do katalogu źródłowego, aby działać na plikach lub zapisywać te same ścieżki plików w kółko, aby wyrazić ścieżki do wszystkich plików. Niedługo zaktualizuję przykład, aby dać czytelnikom lepszy obraz tego, o czym mówię.
cmndr sp0ck
0

W przypadku minimalnej dystrybucji Linuksa powinny działać następujące. Najpierw wykonaj podstawowy ruch wszystkich (co spowoduje pominięcie ukrytych plików). Następnie przenieść wszystkie pliki ukryte (w tym .i ..które nie faktycznie być przeniesiony).

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

Uwagi: Jeśli nie ma widocznej treści, pierwsze polecenie wyświetli komunikat o błędzie. Drugie polecenie zawsze spowoduje błąd informujący, że nie można go przenieść .i ... W związku z tym po prostu potokuj błędy w /dev/null(jak pokazano).

Jeśli potrzebujesz tego jako jednowarstwowego, po prostu połącz je z średnikiem:

mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
BuvinJ
źródło