
W tym artykule omówione zostaną pewne niewidoczne aspekty związane z wykorzystaniem podczas kopiowania, niejednoznaczne zachowanie polecenia cp przy kopiowaniu, a także sposoby pozwalające na poprawne kopiowanie ogromnej liczby plików bez pominięć i błędów.
Załóżmy, że musimy skopiować wszystko z folderu /source do folderu /target.
Pierwsze, co przychodzi do głowy, to:
cp /source/* /targetOd razu poprawimy to polecenie na:
cp -a /source/* /target Klucz -a doda kopię wszystkich atrybutów, praw i włączy rekursję. Gdy nie jest wymagane dokładne odtworzenie praw, wystarczy klucz -r.
Po skopiowaniu stwierdzimy, że nie wszystkie pliki zostały skopiowane - zignorowane zostały pliki zaczynające się od kropki, takie jak:
.profil
.lokalny
.mc
i tym podobne.
Dlaczego tak się stało?
Ponieważ wildcardy są przetwarzane przez powłokę (bash w standardowym przypadku). Domyślnie bash ignoruje wszystkie pliki zaczynające się od kropek, uznając je za ukryte. Aby uniknąć takiego zachowania, musimy zmienić zachowanie bash za pomocą polecenia:
shopt -s dotglob Aby ta zmiana zachowania zachowała się po restarcie, można stworzyć plik wildcard.sh z tym poleceniem w folderze /etc/profile.d (możliwe, że w Twojej dystrybucji jest inny folder).
A jeśli w katalogu źródłowym nie ma plików, to powłoka nie będzie mogła zastąpić gwiazdki, a kopiowanie zakończy się błędem. Na taką sytuację są opcje failglob i nullglob. Będziemy potrzebować ustawić failglob, która nie pozwoli na wykonanie polecenia. nullglob nie zadziała, ponieważ przekształca ciąg z wildcardami, które nie znalazły dopasowania, w pusty ciąg (o zerowej długości), co dla cp spowoduje błąd.
Jednakże, jeśli w folderze jest tysiące plików lub więcej, warto zrezygnować z podejścia z wildcardami. Chodzi o to, że bash rozwinie wildcardy w bardzo długą linię poleceń, podobną do:
cp -a /source/a /source/b /source/c …… /targetNa długość linii poleceń są ograniczenia, które możemy poznać przy użyciu polecenia:
getconf ARG_MAXOtrzymamy maksymalną długość linii poleceń w bajtach:
2097152Lub:
xargs --show-limitsOtrzymamy coś w rodzaju:
….
Maksymalna długość polecenia, które możemy właściwie użyć: 2089314
….Zatem, pozbądźmy się całkowicie wildcardów.
Po prostu napiszmy
cp -a /source /target A tutaj napotkamy na niejednoznaczność zachowania cp. Jeśli katalog /target nie istnieje, otrzymamy to, czego potrzebujemy.
Jednakże, jeśli folder docelowy istnieje, pliki zostaną skopiowane do folderu /target/source.
Nie zawsze możemy wcześniej usunąć folder /target, ponieważ mogą się w nim znajdować potrzebne nam pliki, a naszym celem jest, powiedzmy, uzupełnienie plików w /target plikami z /source.
Gdyby foldery źródłowy i docelowy nazywały się tak samo, na przykład, gdybyśmy kopiowali z /source do /home/source, moglibyśmy użyć polecenia:
cp -a /source /homeI po skopiowaniu pliki w /home/source byłyby uzupełnione plikami z /source.
Oto logiczna zagadka: możemy uzupełnić pliki w katalogu docelowym, jeśli foldery mają te same nazwy, ale jeśli się różnią, folder źródłowy zostanie umieszczony wewnątrz katalogu docelowego. Jak skopiować pliki z /source do /target za pomocą cp bez użycia wildcardów?
Aby obejść to niekorzystne ograniczenie, używamy nieoczywistego rozwiązania:
cp -a /source/. /targetCi, którzy dobrze znają DOS i Linux, już wszystko rozumieją: w każdym folderze znajdują się dwa ukryte foldery «.» i «..», które są pseudokatalogami-linkami do bieżącego i wyższego katalogu.
- Podczas kopiowania
cpsprawdza istnienie i stara się stworzyć /target/. - Taki katalog istnieje i jest to /target.
- Pliki z /source zostały poprawnie skopiowane do /target.
Zatem zapisz w pamięci lub na ścianie:
cp -a /source/. /target
Zachowanie tego polecenia jest jednoznaczne. Wszystko zadziała bez błędów, niezależnie od tego, czy masz milion plików, czy ich nie masz.
Wnioski
Jeśli trzeba skopiować wszystkie pliki z jednego folderu do drugiego, nie używamy wildcardów, zamiast tego lepiej użyć cp w połączeniu z kropką na końcu folderu źródłowego. To skopiuje wszystkie pliki, w tym ukryte, i nie zawiedzie przy milionach plików lub ich braku.
Epilog
zapropnował podobną do rezultatu wersję polecenia:
cp -a -T /source /target
cp -aT /source /target UWAGA: wielkość liter T ma znaczenie. Jeśli się pomylisz, otrzymasz całkowity bałagan: kierunek kopiowania się zmieni.
Podziękowania:
- Firmie za wsparcie i możliwość publikacji na swoim blogu na Habra.
- Za obraz . Obrazek jest bardzo duży i szczegółowy, można go otworzyć w osobnym oknie.
P.S. Zgłaszane błędy proszę kierować na priv. Podnoszę za to karmę.
Źródło: habr.com
