Ta članek bo razkril nekaj neočitnih stvari, povezanih z uporabo nadomestnih znakov pri kopiranju dvoumno obnašanje ukaza cp pri kopiranju, kot tudi metode, ki vam omogočajo pravilno kopiranje ogromnega števila datotek brez preskakovanja ali zrušitve.
Recimo, da moramo kopirati vse iz mape /source v mapo /target.
Prva stvar, ki mi pride na misel, je:
cp /source/* /target
Takoj popravimo ta ukaz na:
cp -a /source/* /target
Ključ -a bo dodal kopiranje vseh atributov, pravic in dodal rekurzijo. Kadar natančna reprodukcija pravic ni potrebna, zadostuje ključ -r.
Po kopiranju bomo ugotovili, da niso bile kopirane vse datoteke – datoteke, ki se začnejo s piko, kot je:
.profile
.local
.mc
in podobni.
Zakaj se je to zgodilo?
Ker nadomestne znake obdela lupina (bash v tipičnem primeru). Privzeto bo bash prezrl vse datoteke, ki se začnejo s pikami, saj jih obravnava kot skrite. Da bi se izognili temu vedenju, bomo morali spremeniti vedenje bash z uporabo ukaza:
shopt -s dotglob
Če želite zagotoviti, da se ta sprememba vedenja ohrani tudi po vnovičnem zagonu, lahko ustvarite datoteko wildcard.sh s tem ukazom v mapi /etc/profile.d (Morda ima vaša distribucija drugo mapo).
In če v izvornem imeniku ni datotek, potem lupina ne bo mogla ničesar nadomestiti namesto zvezdice, kopiranje pa bo tudi neuspešno z napako. Obstajajo možnosti proti tej situaciji failglob и nullglob. Morali bomo nastaviti failglob, ki bo preprečil izvedbo ukaza. nullglob ne bo delovalo, saj pretvori niz z nadomestnimi znaki, ki niso našli ujemanja, v prazen niz (dolžine nič), kar za cp bo povzročil napako.
Če pa je v mapi na tisoče datotek ali več, je treba pristop z nadomestnimi znaki v celoti opustiti. Dejstvo je, da bash razširi nadomestne znake v zelo dolgo ukazno vrstico, kot je:
cp -a /souce/a /source/b /source/c …… /target
Obstaja omejitev dolžine ukazne vrstice, ki jo lahko ugotovimo z ukazom:
getconf ARG_MAX
Dobimo največjo dolžino ukazne vrstice v bajtih:
2097152
Или:
xargs --show-limits
Dobimo nekaj takega:
….
Maximum length of command we could actually use: 2089314
….
Torej, opustimo nadomestne znake.
Samo napišimo
cp -a /source /target
In tu se soočamo z dvoumnostjo obnašanja cp. Če mapa /target ne obstaja, bomo dobili tisto, kar potrebujemo.
Če pa ciljna mapa obstaja, bodo datoteke kopirane v mapo /target/source.
Mape /target ne moremo vedno vnaprej izbrisati, ker lahko vsebuje datoteke, ki jih potrebujemo, naš cilj pa je na primer dopolniti datoteke v /target z datotekami iz /source.
Če bi bili izvorna in ciljna mapa poimenovani enako, na primer kopirali bi iz /source v /home/source, bi lahko uporabili ukaz:
cp -a /source /home
In po kopiranju bi bile datoteke v /home/source dopolnjene z datotekami iz /source.
To je logična težava: datoteke lahko dodamo v ciljni imenik, če so mape poimenovane enako, če pa se razlikujejo, bo izvorna mapa postavljena znotraj ciljne mape. Kako kopirati datoteke iz /source v /target z uporabo cp brez nadomestnih znakov?
Da bi se izognili tej škodljivi omejitvi, uporabljamo neočitno rešitev:
cp -a /source/. /target
Tisti, ki poznajo DOS in Linux, so že razumeli vse: v vsaki mapi sta 2 nevidni mapi "." in “..”, ki sta psevdo-mape, povezave do trenutnih in višjih imenikov.
Pri kopiranju cp preveri obstoj in poskuša ustvariti /target/.
Tak imenik obstaja in je /target
Datoteke iz /source so pravilno kopirane v /target.
Torej, obesite ga v krepkem okvirju v spomin ali na steno:
cp -a /source/. /target
Vedenje tega ukaza je jasno. Vse bo delovalo brez napak, ne glede na to ali imate milijon datotek ali pa nobene.
Ugotovitve
Če morate kopirati Vsi datoteke iz ene mape v drugo, ne uporabljamo nadomestnih znakov, bolje jih je uporabiti cp skupaj s piko na koncu izvorne mape. To bo kopiralo vse datoteke, vključno s skritimi, in ne bo uspelo z milijoni datotek ali nobene datoteke.
spremna beseda
vmspike predlagal različico ukaza s podobnim rezultatom: