cp-kommando: korrekt kopiering av filmapper i *nix
Denne artikkelen vil avsløre noen ikke-åpenbare ting knyttet til bruken av jokertegn ved kopiering, tvetydig kommandoadferd cp når du kopierer, samt metoder som lar deg kopiere et stort antall filer riktig uten å hoppe over eller krasje.
La oss si at vi må kopiere alt fra /source-mappen til /target-mappen.
Det første du tenker på er:
cp /source/* /target
La oss umiddelbart rette denne kommandoen til:
cp -a /source/* /target
Ключ -a vil legge til kopiering av alle attributter, rettigheter og legge til rekursjon. Når nøyaktig gjengivelse av rettigheter ikke er nødvendig, er en nøkkel tilstrekkelig -r.
Etter kopiering vil vi oppdage at ikke alle filene ble kopiert - filer som starter med en prikk som:
.profile
.local
.mc
o.l.
Hvorfor skjedde dette?
Fordi jokertegn behandles av skallet (bash i et typisk tilfelle). Som standard vil bash ignorere alle filer som starter med prikker, da den behandler dem som skjulte. For å unngå denne oppførselen må vi endre atferd bash ved å bruke kommandoen:
shopt -s dotglob
For å sikre at denne atferdsendringen vedvarer etter en omstart, kan du opprette en wildcard.sh-fil med denne kommandoen i mappen /etc/profile.d (Kanskje distribusjonen din har en annen mappe).
Og hvis det ikke er noen filer i kildekatalogen, vil ikke skallet kunne erstatte noe i stedet for stjernen, og kopiering vil også mislykkes med en feil. Det finnes alternativer mot denne situasjonen failglob и nullglob. Vi må sette failglob, som vil forhindre at kommandoen blir utført. nullglob vil ikke fungere, siden den konverterer en streng med jokertegn som ikke fant samsvar til en tom streng (null lengde), som for cp vil forårsake en feil.
Men hvis det er tusenvis av filer eller flere i mappen, bør jokertegnsmetoden forlates helt. Faktum er det bash utvider jokertegn til en veldig lang kommandolinje som:
cp -a /souce/a /source/b /source/c …… /target
Det er en grense for lengden på kommandolinjen, som vi kan finne ut ved å bruke kommandoen:
getconf ARG_MAX
La oss få den maksimale lengden på kommandolinjen i byte:
2097152
Или:
xargs --show-limits
Vi får noe sånt som:
….
Maximum length of command we could actually use: 2089314
….
Så la oss klare oss helt uten jokertegn.
La oss bare skrive
cp -a /source /target
Og her står vi overfor tvetydighet i oppførselen cp. Hvis /target-mappen ikke eksisterer, får vi det vi trenger.
Men hvis målmappen eksisterer, vil filene bli kopiert til /target/source-mappen.
Vi kan ikke alltid slette /target-mappen på forhånd, siden den kan inneholde filer vi trenger og målet vårt for eksempel er å supplere filene i /target med filer fra /source.
Hvis kilde- og målmappen ble navngitt det samme, for eksempel kopierte vi fra /kilde til /hjem/kilde, så kunne vi bruke kommandoen:
cp -a /source /home
Og etter kopiering vil filene i /home/source bli supplert med filer fra /source.
Dette er et logisk problem: vi kan legge til filer i målkatalogen hvis mappene heter det samme, men hvis de er forskjellige, vil kildemappen bli plassert inne i destinasjonen. Hvordan kopiere filer fra /source til /target ved hjelp av cp uten jokertegn?
For å omgå denne skadelige begrensningen bruker vi en ikke-åpenbar løsning:
cp -a /source/. /target
De som er kjent med DOS og Linux har allerede forstått alt: inne i hver mappe er det 2 usynlige mapper "." og "..", som er pseudo-mapper lenker til gjeldende og høyere kataloger.
Ved kopiering cp sjekker om det finnes og prøver å lage /target/.
En slik katalog finnes og det er /target
Filer fra /source er kopiert til /target på riktig måte.
Så heng den i en dristig ramme i minnet eller på veggen:
cp -a /source/. /target
Oppførselen til denne kommandoen er tydelig. Alt vil fungere uten feil, uansett om du har en million filer eller ingen i det hele tatt.
Funn
Hvis du trenger å kopiere alle filer fra en mappe til en annen, vi bruker ikke jokertegn, det er bedre å bruke dem i stedet cp kombinert med et punktum på slutten av kildemappen. Dette vil kopiere alle filer, inkludert skjulte, og vil ikke mislykkes med millioner av filer eller ingen filer i det hele tatt.
etterord
vmspike foreslo en kommandoversjon med et lignende resultat: