Hogyan másolhatunk mappát rekurzív módon idempotens módon a cp használatával?
On december 1, 2020 by adminAmikor használom
cp -R inputFolder outputFolder
az eredmény kontextustól függő :
- ha
outputFolder
nem létezik, akkor létrejön, és a klónozott mappa elérési útjaoutputFolder
lesz. - ha létezik
outputFolder
, akkor a létrehozott klón beoutputFolder/inputFolder
Ez borzalmas , mert szeretnék létrehozni egy telepítési parancsfájlt, és ha a felhasználó tévedésből kétszer futtatja, akkor először létrehozni fogja a outputFolder
fájlt, majd a második futtatáskor az összes dolog újra létre kell hozni a outputFolder/inputFolder
fájlban.
- Mindig az első viselkedést szeretném: hozzon létre egy klónt az eredeti mellett (testvérként).
- A
cp
-t hordozhatónak szeretném használni (pl. A MINGW nemrsync
kiszállított) - Ellenőriztem a
cp -R --parents
elemet, de ez újból létrehozza az utat a könyvtárfáig (tehát a klón nemoutputFolder
lesz, hanemsome/path/outputFolder
) -
--remove-destination
vagy--update
abban az esetben, ha a 2. nem változtat semmin, a dolgok átmásolódnak aoutputFolder/inputFolder
van rá mód anélkül, hogy először ellenőriznénk a outputFolder
létezését (ha akkor még nem létezik mappa …), vagy a rm -rf outputFolder
?
Mi a megbeszélt, hordozható UNIX módszer erre?
Megjegyzések
Válasz
Ezt használja inkább:
cp -R inputFolder/. outputFolder
Ez pontosan ugyanúgy működik, mint mondjuk cp -R aaa/bbb ccc
: ha ccc
nem létezik, akkor ” a bbb
és annak tartalmának másolataként hozták létre; de ha ccc
már létezik, akkor a ccc/bbb
a bbb
és annak tartalmának másolataként jön létre .
A bbb
szinte minden példányához ez adja azt a nemkívánatos viselkedést, amelyet a kérdésében megjegyzett. Ebben a konkrét helyzetben azonban a bbb
csak .
, tehát aaa/bbb
valóban aaa/.
, ami viszont valójában csak aaa
, hanem egy másik név. Tehát ez a két forgatókönyv áll rendelkezésünkre:
-
ccc
nem létezik:A jelentése:” létrehozás
ccc
és azaaa/.
tartalmának átmásolása accc/.
, azaz másolja aaaa
elemet accc
fájlba. -
ccc
létezik:A
cp -R aaa/. ccc
parancs azt jelenti, hogy” másolja azaaa/.
ccc/.
, azaz másolja aaaa
elemet accc
fájlba.
Megjegyzések
- Huh, ez ‘ nekem új, de úgy tűnik, hogy működik! Ez bárhol dokumentálva van?
- Én ‘ teszteltem a
inputFolder/.
-t ainputFolder
és valóban működik a Windows / Git Bash rendszeren. (Ez azonban nem működik csak egy lemaradó/
esetén, a perjel utáni pontra is szükségem van).+1-et adtam, mivel ‘ érdekes, bár ‘ valószínűleg túl bonyolult ahhoz, hogy a nyilvános kódban használjam:) - @IlmariJaronen nem kell ‘ ezt kifejezetten dokumentálni. Kövesse a magyarázatot, és ‘ meglátja, hogy egyszerűen ” hogyan követi a ” szabályokat .
Válasz
Ne másolja a mappát, csak a tartalmát másolja át:
## 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/
Így mindketten győződjünk meg arról, hogy a célkönyvtár a szkript első futtatásakor jön létre, és kerüljük a probléma, amikor másodszor futtatja.
Chris Down nagyon helyesen rámutat, hogy a bash-ban ez kihagyja azokat a fájlokat, amelyek neve .
-vel kezdődik. Ennek elkerülése érdekében , a fenti parancs futtatása előtt futtathatja a shopt -s dotglob
parancsot.
Mindkét -p
mkdir
és -R
esetén cp
a POSIX határozza meg, ezért ennek tökéletesen hordozhatónak kell lennie.
Megjegyzések
- Megjegyzés: ez nem fog ‘ t másolni a
.
kezdetű fájlokkal. A bash-ban ehhez használhatja adotglob
-t. - Vegye figyelembe, hogy ez a módszer valószínűleg meghiúsul, ha az inputmappában nagy a könyvtárbejegyzések száma, mert a globális kiterjesztés meghaladhatja a parancssor maximális hosszát.
Válasz
Próbálja ki a -T
opció a cp
opcióra. Ez a GNU coreutils cp
8.22-es verzióban létezik; lehet, hogy ezen kívül nem hordozható.
Megjegyzések
- Igen, úgy tűnik, hogy pontosan ezt akartam:
cp -T
(cp --no-target-directory
). unix.stackexchange.com/questions/94831/… Sajnos acp
sokkal régebbi. - +1 Ezt ma használta. A
-u
nagyszerű lehetőség, hogy lustává tegye.
Válasz
Használhatja a következőt is: rsync
:
rsync -uav inputFolder/ outputFolder/
(vegye figyelembe a perjeleket, különösen az első után )
Válasz
Használhatja a -t
opciót a cp
parancs:
cp -R inputFolder -t outputFolder
most, ha a célmappa nem létezik, hibát fog dobni:
cp: failed to access ‘outputFolder’: No such file or directory
A fenti megjegyzés a inputFolder
-t a tartalmával együtt (és nem csak a benne lévő tartalommal) másolja.
ha szeretné csak a inputFolder
tartalmának másolása kissé bonyolulttá válik (mivel körültekintőnek kell lenned, amikor a csillagot használod, miközben csillagot használ *)
cp -R -t outputFolder/ -- inputFolder/*
ha nem létezik célmappa, akkor hibát fog okozni:
cp: failed to access ‘outputFolder’: No such file or directory
a cp (GNU coreutils) 8.23
Válasz
Véleményem szerint nincs semmi egyszerűbb és hordozhatóbb, mint a rm -rf outputFolder
. Tehát mindig kitartok mellettem. Megértem, hogy a kérdése más, de úgy gondolom, hogy ez a legjobb gyakorlat.
Megjegyzések
- Ez nem sikerül, ha vannak külön engedélyek vagy tulajdonjogok azon a célponton, amelyet meg kellett tartani. Vagy ha symlink volt.
- A kérdés azt akarja, hogy az
cp
eredménye azonos legyen, akkor is, ha a könyvtár nem létezik, és amikor létezik. Tehát miről beszélsz? - Az
cp
parancs, amelyet az OP adott meg, nem tartja meg az engedélyeket ‘ (vagy időbélyegek).
mv
fájlgyűjteményt egyetlen rendesbe helyezze?rsync
szolgáltatást?cp
-t kell használnia, a kéttar
parancs közötti csővezetékezés megbízható módszer a fák másolására.rsync
.tar -C input -cf - . | tar -C output -xf -
működik. A-C
megváltoztatja a munkakönyvtárat, de ez nem egy szokásos opció, így ha ‘ nem támogatott, akkor futtatnia kell a két tar-t a megfelelő működő könyvtárakat, pl( cd input && tar -cf - . ) | ( cd output && tar -xf - )
Ha azonban ‘ a Windows rendszerrel foglalkozik, akkor csak a roaima ‘ válaszokat használnám .