Hvordan kopieres en mappe rekursivt på en idempotent måde ved hjælp af cp?
On december 1, 2020 by adminNår jeg bruger
cp -R inputFolder outputFolder
er resultatet kontekstafhængig :
- hvis
outputFolder
ikke findes, vil den være oprettes, og den klonede mappesti vil væreoutputFolder
. - Hvis
outputFolder
eksisterer, vil den oprettede klon være væreoutputFolder/inputFolder
Dette er forfærdeligt , fordi jeg vil oprette et installationsscript, og hvis brugeren ved en fejltagelse kører det to gange, vil han have outputFolder
oprettet første gang, så på det andet løb vil alle ting oprettes igen i outputFolder/inputFolder
.
- Jeg vil altid have den første adfærd: Opret en klon ved siden af originalen (som et søskende).
- Jeg vil bruge
cp
til at være bærbar (f.eks. MINGW ikke harrsync
afsendt) - Jeg tjekkede
cp -R --parents
men dette genskaber stien helt op til katalogtræet (så klonen vil ikke væreoutputFolder
mensome/path/outputFolder
) -
--remove-destination
eller--update
hvis 2 ikke ændrer noget, stadig kopieres ting tiloutputFolder/inputFolder
Er der er en måde at gøre dette uden først at kontrollere for eksistensen af outputFolder
(hvis mappen ikke eksisterer så …) eller bruge rm -rf outputFolder
?
Hvad er den aftalte, bærbare UNIX-måde at gøre det på?
Kommentarer
Svar
Brug dette i stedet:
cp -R inputFolder/. outputFolder
Dette fungerer på nøjagtig samme måde som f.eks. cp -R aaa/bbb ccc
fungerer: hvis ccc
ikke eksisterer, så er det ” s oprettet som en kopi af bbb
og dens indhold; men hvis ccc
allerede findes, oprettes ccc/bbb
som kopien af bbb
.
For næsten enhver forekomst af bbb
giver dette den uønskede adfærd, som du bemærkede i dit spørgsmål. I denne specifikke situation er bbb
dog kun .
, så aaa/bbb
er virkelig aaa/.
, som igen bare er aaa
men med et andet navn. Så vi har disse to scenarier:
-
ccc
findes ikke:Kommandoen
cp -R aaa/. ccc
betyder” opretccc
og kopier indholdet afaaa/.
tilccc/.
, dvs. kopieraaa
tilccc
. -
ccc
findes:Kommandoen
cp -R aaa/. ccc
betyder” kopier indholdet afaaa/.
ccc/.
, dvs. kopieraaa
tilccc
.
Kommentarer
- Huh, at ‘ er en ny for mig, men det ser ud til at fungere! Er dette dokumenteret hvor som helst?
- Jeg ‘ har testet
inputFolder/.
i stedet forinputFolder
og faktisk fungerer det for mig på Windows / Git Bash. (Det fungerer dog ikke med bare en efterfølgende/
, jeg har også brug for prikken efter skråstreg).Jeg gav +1, da det ‘ er interessant, selvom det ‘ sandsynligvis er lidt for vanskeligt at bruge det i offentlig kode:) - @IlmariJaronen det behøver ikke ‘ at blive dokumenteret eksplicit. Følg forklaringen, og du ‘ vil se, hvordan det bare ” følger reglerne ” .
Svar
Du må ikke kopiere mappen, kun kopiere indholdet:
## Create the target directory. The -p suppresses error messages ## if the directory already exists mkdir -p outputFolder ## Copy the contents recursively, this will not recreate the parent cp -R inputfolder/* outputfolder/
På denne måde sikrer du begge, at målmappen oprettes første gang scriptet kører, og undgår problem, når du kører det en anden gang.
Chris Down påpeger meget korrekt, at dette i bash springer filer over, hvis navn starter med en .
. For at undgå dette , kan du køre shopt -s dotglob
før du kører kommandoen ovenfor.
Begge -p
til mkdir
og -R
til cp
er defineret af POSIX, så dette skal være perfekt bærbart.
Kommentarer
- Bemærk: dette vandt ‘ t kopierer filer startende med
.
. I bash kan du brugedotglob
til det. - Bemærk, at denne metode sandsynligvis mislykkes, hvis antallet af biblioteksposter i inputmappen er stort, fordi glob-ekspansionen kan overstige den maksimale kommandolinjelængde.
Svar
Prøv -T
mulighed for at cp
. Dette findes i GNU coreutils cp
version 8.22; det er muligvis ikke bærbart uden for det.
Kommentarer
- Ja, det ser ud til, at det er netop det, jeg ville have:
cp -T
(cp --no-target-directory
). unix.stackexchange.com/questions/94831/… Desværre er min version afcp
er meget ældre. - +1 Brugte dette lige i dag.
-u
er en god mulighed at tilføje for at gøre den doven.
Svar
Du kan også bruge rsync
:
rsync -uav inputFolder/ outputFolder/
(bemærk skråstreger, især efter den første )
Svar
Du kan bruge -t
mulighed for cp
kommando som:
cp -R inputFolder -t outputFolder
nu hvis målmappen ikke findes, vil den kaste en fejl:
cp: failed to access ‘outputFolder’: No such file or directory
note ovenfor kommando vil kopiere inputFolder
sammen med dets indhold (og ikke kun indholdet inde i det)
hvis du vil for kun at kopiere indholdet af inputFolder
bliver det lidt vanskeligt (da du skal være forsigtig, når du bruger shell globbing, mens du bruger en stjerne *)
cp -R -t outputFolder/ -- inputFolder/*
nu hvis målmappen ikke findes, kaster den en fejl:
cp: failed to access ‘outputFolder’: No such file or directory
fungerer med cp (GNU coreutils) 8.23
Svar
Efter min mening er der intet enklere og mere bærbart end rm -rf outputFolder
. Så det holder jeg altid med. Jeg forstår, at dit spørgsmål er anderledes, men jeg synes, at dette er den bedste praksis.
Kommentarer
- Det mislykkes, hvis der var specifikke tilladelser eller ejerskaber på det mål, der skulle holdes. Eller hvis det var et symlink.
- Spørgsmålet ønsker, at resultatet af
cp
skal være det samme, både når biblioteket ikke findes, og når det findes. Så hvad taler du om? -
cp
kommandoen som givet af OPen holder ikke ‘ t (eller tidsstempler).
mv
i at flytte en samling filer til en enkelt almindelig?rsync
?cp
, rør mellem totar
kommandoer er en dejlig pålidelig måde at kopiere træer på.rsync
sendt.tar -C input -cf - . | tar -C output -xf -
fungerer.-C
skifter arbejdsmappe, men det er ikke en standardindstilling, så hvis den ‘ ikke understøttes, skal du køre de to søjler i de rigtige arbejdsmapper til at begynde med, f.eks( cd input && tar -cf - . ) | ( cd output && tar -xf - )
Men hvis du ‘ har at gøre med Windows, ville jeg bare bruge roaima ‘ s svar .