cp-opdracht: bestandsmappen correct kopiëren in *nix
Dit artikel zal enkele niet voor de hand liggende zaken onthullen die verband houden met het gebruik van wildcards bij het kopiëren, dubbelzinnig opdrachtgedrag cp bij het kopiëren, evenals methoden waarmee u een groot aantal bestanden correct kunt kopiëren zonder over te slaan of te crashen.
Laten we zeggen dat we alles van de map /source naar de map /target moeten kopiëren.
Het eerste dat in je opkomt is:
cp /source/* /target
Laten we deze opdracht onmiddellijk corrigeren om:
cp -a /source/* /target
sleutel -a voegt het kopiëren van alle attributen en rechten toe en voegt recursie toe. Wanneer exacte reproductie van rechten niet vereist is, is een sleutel voldoende -r.
Na het kopiëren zullen we ontdekken dat niet alle bestanden zijn gekopieerd - bestanden die beginnen met een punt zoals:
.profile
.local
.mc
en dergelijke.
Waarom is dit gebeurd?
Omdat jokertekens worden verwerkt door de shell (bash in een typisch geval). Standaard negeert bash alle bestanden die met punten beginnen, omdat deze als verborgen worden behandeld. Om dit gedrag te voorkomen zullen we gedrag moeten veranderen bash met behulp van de opdracht:
shopt -s dotglob
Om ervoor te zorgen dat deze gedragsverandering na een herstart blijft bestaan, kunt u met deze opdracht een wildcard.sh-bestand in de map maken /etc/profile.d (Misschien heeft uw distributie een andere map).
En als er geen bestanden in de bronmap staan, kan de shell niets vervangen in de plaats van het sterretje, en zal het kopiëren ook mislukken met een fout. Er zijn opties tegen deze situatie failglob и nullglob. We zullen moeten instellen failglob, waardoor de opdracht niet kan worden uitgevoerd. nullglob zal niet werken, omdat het een string met jokertekens die geen overeenkomst heeft gevonden, omzet in een lege string (lengte nul), die cp zal een fout veroorzaken.
Als er echter duizenden bestanden of meer in de map staan, moet de aanpak met jokertekens helemaal worden verlaten. Het feit is dat bash breidt jokertekens uit naar een zeer lange opdrachtregel, zoals:
cp -a /souce/a /source/b /source/c …… /target
Er is een limiet aan de lengte van de opdrachtregel, die we kunnen achterhalen met behulp van de opdracht:
getconf ARG_MAX
Laten we de maximale lengte van de opdrachtregel in bytes bepalen:
2097152
Или:
xargs --show-limits
We krijgen zoiets als:
….
Maximum length of command we could actually use: 2089314
….
Laten we het dus helemaal zonder jokertekens doen.
Laten we gewoon schrijven
cp -a /source /target
En hier worden we geconfronteerd met dubbelzinnigheid van gedrag cp. Als de map /target niet bestaat, krijgen we wat we nodig hebben.
Als de doelmap echter bestaat, worden de bestanden gekopieerd naar de map /target/source.
We kunnen de map /target niet altijd vooraf verwijderen, omdat deze bestanden kan bevatten die we nodig hebben en ons doel bijvoorbeeld is om de bestanden in /target aan te vullen met bestanden uit /source.
Als de bron- en doelmappen dezelfde naam hadden, bijvoorbeeld als we aan het kopiëren waren van /source naar /home/source, dan zouden we de opdracht kunnen gebruiken:
cp -a /source /home
En na het kopiëren zouden de bestanden in /home/source worden aangevuld met bestanden uit /source.
Dit is een logisch probleem: we kunnen bestanden toevoegen aan de doelmap als de mappen dezelfde naam hebben, maar als ze verschillend zijn, wordt de bronmap in de doelmap geplaatst. Hoe kopieer ik bestanden van /source naar /target met behulp van cp zonder jokertekens?
Om deze schadelijke beperking te omzeilen, gebruiken we een niet voor de hand liggende oplossing:
cp -a /source/. /target
Degenen die bekend zijn met DOS en Linux hebben alles al begrepen: in elke map bevinden zich 2 onzichtbare mappen “.” en “..”, dit zijn pseudo-mappen die verwijzen naar de huidige en hogere mappen.
Bij het kopiëren cp controleert op bestaan en probeert /target/ aan te maken.
Zo'n map bestaat en deze is /target
Bestanden van /source worden correct gekopieerd naar /target.
Hang het dus in een opvallende lijst ter nagedachtenis of aan de muur:
cp -a /source/. /target
Het gedrag van dit commando is duidelijk. Alles werkt zonder fouten, ongeacht of u een miljoen bestanden heeft of helemaal geen.
Bevindingen
Als u wilt kopiëren alle bestanden van de ene map naar de andere, we gebruiken geen jokertekens, het is beter om ze in plaats daarvan te gebruiken cp gecombineerd met een punt aan het einde van de bronmap. Hiermee worden alle bestanden gekopieerd, inclusief verborgen bestanden, en dit zal niet mislukken als er miljoenen bestanden of helemaal geen bestanden zijn.
nawoord
vmspike stelde een commandoversie voor met een vergelijkbaar resultaat: