Cum se copiază un dosar recursiv într-un mod idempotent folosind cp?
On decembrie 1, 2020 by adminCând folosesc
cp -R inputFolder outputFolder
rezultatul este dependent de context :
- dacă
outputFolder
nu există, va exista fi creat, iar calea folderului clonat va fioutputFolder
. - dacă există
outputFolder
, atunci clona creată va fi fioutputFolder/inputFolder
Acest lucru este oribil , deoarece vreau să creez un script de instalare și, dacă utilizatorul îl execută de două ori din greșeală, va avea outputFolder
creat prima dată, apoi la a doua rulare toate lucrurile vor fi fi creat încă o dată în outputFolder/inputFolder
.
- Vreau întotdeauna primul comportament: creați o clonă lângă original (ca frate).
- Vreau să folosesc
cp
pentru a fi portabil (de ex. MINGW nu aursync
livrat) - Am verificat
cp -R --parents
, dar aceasta recreează calea până în arborele directorului (deci clona nu va fioutputFolder
cisome/path/outputFolder
) -
--remove-destination
sau--update
în cazul în care 2 nu schimbă nimic, totuși lucrurile sunt copiate înoutputFolder/inputFolder
există o modalitate de a face acest lucru fără a verifica mai întâi existența outputFolder
(dacă folderul nu există atunci …) sau folosind rm -rf outputFolder
?
Care este modul UNIX convenit și portabil de a face acest lucru?
Comentarii
Răspuns
Folosiți acest lucru în schimb:
cp -R inputFolder/. outputFolder
Acest lucru funcționează exact în același mod în care, să zicem, funcționează cp -R aaa/bbb ccc
: dacă ccc
„nu există, atunci” s-a creat ca o copie a bbb
și a conținutului acestuia; dar dacă ccc
există deja, atunci ccc/bbb
este creat ca copie a bbb
și conținutul acestuia .
Pentru aproape orice caz de bbb
, acesta oferă comportamentul nedorit pe care l-ați observat în întrebarea dvs. Cu toate acestea, în această situație specifică bbb
este doar .
, deci aaa/bbb
este într-adevăr aaa/.
, care la rândul său este cu adevărat doar aaa
, dar cu un alt nume. Deci avem aceste două scenarii:
-
ccc
nu există:Comanda
cp -R aaa/. ccc
înseamnă” creațiccc
și copiați conținutulaaa/.
înccc/.
, adică copiațiaaa
înccc
. -
ccc
există:Comanda
cp -R aaa/. ccc
înseamnă” copiați conținutulaaa/.
ccc/.
, adică copiațiaaa
înccc
.
Comentarii
- Huh, că ‘ este unul nou pentru mine, dar pare să funcționeze! Este documentat oriunde?
- Am ‘ testat
inputFolder/.
în loc deinputFolder
și într-adevăr funcționează pentru mine pe Windows / Git Bash. (Nu funcționează totuși doar cu un/
final, am nevoie și de punctul după bară).Am dat +1 deoarece ‘ este interesant, deși probabil ‘ este puțin prea dificil pentru a-l folosi în codul public:) - @IlmariJaronen nu trebuie să fie documentat în mod explicit ‘ Urmăriți explicația și ‘ veți vedea cum pur și simplu ” respectă regulile ” .
Răspuns
Nu copiați folderul, copiați doar conținutul:
## 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/
Astfel vă asigurați că directorul țintă este creat prima dată când rulează scriptul și evitați problemă când îl rulați a doua oară.
Chris Down subliniază foarte corect că în bash, acesta va sări peste fișierele al căror nume începe cu un .
. , puteți rula shopt -s dotglob
înainte de a rula comanda de mai sus.
Ambele -p
pentru mkdir
și -R
pentru cp
sunt definite de POSIX, deci acest lucru ar trebui să fie perfect portabil.
Comentarii
- Notă: acest lucru nu va câștiga ‘ pentru a copia fișiere începând cu
.
. În bash, puteți utilizadotglob
pentru asta. - Rețineți că această metodă poate eșua dacă numărul de intrări de director din folderul de intrare este mare, deoarece extinderea glob ar putea depăși lungimea maximă a liniei de comandă.
Răspuns
Încercați -T
opțiune către cp
. Aceasta există în GNU coreutils cp
versiunea 8.22; s-ar putea să nu fie portabil în afară de asta.
Comentarii
- Da, se pare că exact asta am vrut:
cp -T
(cp --no-target-directory
). unix.stackexchange.com/questions/94831/… Din păcate, versiunea mea decp
este mult mai vechi. - +1 Am folosit acest lucru chiar astăzi.
-u
este o opțiune excelentă de adăugat pentru a face leneșul.
Răspuns
De asemenea, puteți utiliza rsync
:
rsync -uav inputFolder/ outputFolder/
(rețineți barele, mai ales după prima )
Răspuns
Puteți utiliza opțiunea -t
a cp
comanda ca:
cp -R inputFolder -t outputFolder
acum dacă folderul țintă nu există, va arunca o eroare:
cp: failed to access ‘outputFolder’: No such file or directory
comanda de mai sus va copia inputFolder
împreună cu conținutul său (și nu doar conținutul din interior)
dacă doriți pentru a copia doar conținutul inputFolder
devine puțin dificil (deoarece trebuie să fii atent când folosești shell globbing în timp ce folosești asterisc *)
cp -R -t outputFolder/ -- inputFolder/*
acum dacă folderul țintă nu există, va genera o eroare:
cp: failed to access ‘outputFolder’: No such file or directory
funcționează cu cp (GNU coreutils) 8.23
Răspuns
În opinia mea, nu există nimic mai simplu și mai portabil decât rm -rf outputFolder
. Deci, rămân mereu cu asta. Înțeleg că întrebarea dvs. este diferită, dar cred că aceasta este cea mai bună practică.
Comentarii
- Acest lucru nu reușește dacă au existat permisiuni specifice sau proprietăți asupra țintei care trebuia păstrată. Sau dacă a fost un link simbolic.
- Întrebarea dorește ca rezultatul
cp
să fie același, atât atunci când directorul nu există, cât și când acesta există. Deci, despre ce vorbiți? - Comanda
cp
așa cum este dată de OP nu ‘ nu păstrează permisiunile (sau marcaje de timp).
mv
să mute o colecție de fișiere într-o singură regulată?rsync
?cp
, canalizarea între două comenzitar
este o modalitate fiabilă de copiere a copacilor.rsync
livrat.tar -C input -cf - . | tar -C output -xf -
funcționează.-C
modifică directorul de lucru, dar nu este o opțiune standard, deci dacă ‘ nu este acceptat, trebuie să rulați cele două taruri în directoarele de lucru potrivite pentru început, de exemplu( cd input && tar -cf - . ) | ( cd output && tar -xf - )
Cu toate acestea, dacă ‘ aveți de-a face cu Windows, aș folosi doar răspunsul roaima ‘ .