Zaakceptowana odpowiedź jest zła (istnieje taka opcja dla cp). Zobacz drugą odpowiedź Paula Whippa.
Ronenz
1
@Ronenz, zgadzam się, że w GNU istnieje opcja, o której warto wspomnieć cp(na co odpowiedział Paul Whipp), ale nie jest ona tak ogólna, jak wymagała PO. Może kopiować a/foo/bar/filedo, b/foo/bar/fileale nie może kopiować filedo b/foo/bar/file. (tzn. działa tylko w celu utworzenia katalogów nadrzędnych, które już istniały w przypadku pierwszego pliku, ale nie można utworzyć dowolnych katalogów)
Sudo Bash
To wygląda na ładną prośbę o funkcję dla CP. Czy jest jakaś szansa, że w najbliższej przyszłości uda nam się uzyskać przełącznik linii poleceń?
Nie sądzę, że potrzebujesz test -d: mkdir -pnadal działa, nawet jeśli katalog już istnieje.
ephemient
ups, racja. Ale wtedy, test może być polecenie wbudowane bash (zwłaszcza jeśli zapisać jako [[-d "$ d"]]) i mkdir nie może ;-)
Michael Krelin - haker
1
mkdirjest wbudowany w BusyBox;)
ephemient
7
@holms, $djest zmienną, która prawdopodobnie zawiera dany katalog. Chodzi mi o to, że jeśli musisz powtórzyć trzy razy, prawdopodobnie najpierw przypisasz go do zmiennej.
Michael Krelin - haker
237
Jeśli oba poniższe warunki są prawdziwe:
Używasz wersji GNU cp(a nie na przykład wersji Mac) i
Kopiujesz z istniejącej struktury katalogów i po prostu potrzebujesz jej odtworzyć
--parents
Form the name of each destination file by appending to the target
directory a slash and the specified name of the source file. The
last argument given to `cp' must be the name of an existing
directory. For example, the command:
cp --parents a/b/c existing_dir
copies the file `a/b/c' to `existing_dir/a/b/c', creating any
missing intermediate directories.
Przykład:
/tmp $ mkdir foo
/tmp $ mkdir foo/foo
/tmp $ touch foo/foo/foo.txt
/tmp $ mkdir bar
/tmp $ cp --parents foo/foo/foo.txt bar
/tmp $ ls bar/foo/foo
foo.txt
To nie działa w systemie Mac OS X, więc myślę, że jest to specyficzne dla systemu Linux.
ol
7
Powiedziałbym, że specyficzne dla GNU. Jeśli masz macports, możesz zainstalować coreutils i jego gcp.
Michael Krelin - haker
16
Człowieku, Linux ma wszystko
Ziggy
19
Wydaje mi się, że jest to odpowiedź na nieco inne pytanie, mimo że to była odpowiedź, której szukałem (i dlatego ta, którą głosowałem). Sądzę, że jest to rozwiązanie przy założeniu, że chcesz, aby docelowe katalogi nadrzędne były takie same jak katalogi nadrzędne pochodzenia, co jest prawdopodobnie przypadkiem użycia, w którym większość osób czytających to jest interesujące.
David Winiecki
7
Zakłada się, że „pasek” katalogu już istnieje, ale oryginalne pytanie sugeruje, jak automatycznie utworzyć „pasek”, gdy jest podany jako miejsce docelowe i nie istnieje. Odpowiedź na to pytanie zapewnia @ MichaelKrelin-hacker.
thdoan
69
Krótka odpowiedź
Aby skopiować myfile.txtdo /foo/bar/myfile.txt, użyj:
mkdir -p /foo/bar && cp myfile.txt $_
Jak to działa?
Składa się na to kilka elementów, więc krok po kroku omówię całą składnię.
Wreszcie, $_drugi argument podajemy jako cp„specjalny parametr”, który może być przydatny, aby uniknąć powtarzania długich argumentów (takich jak ścieżki plików) bez konieczności przechowywania ich w zmiennej. Zgodnie z instrukcją Bash :
rozwija się do ostatniego argumentu do poprzedniego polecenia
W tym przypadku do /foo/bartego przeszliśmy mkdir. Tak więc cppolecenie rozwija się do cp myfile.txt /foo/bar, który kopiuje myfile.txtdo nowo utworzonego /foo/barkatalogu.
Zauważ, że nie$_ jest to część standardu POSIX , więc teoretycznie wariant Uniksa może mieć powłokę, która nie obsługuje tej konstrukcji. Jednak nie znam żadnych nowoczesnych powłok, które nie obsługują $_; Z pewnością Bash, Dash i Zsh.
Ostatnia uwaga: polecenie, które wydałem na początku tej odpowiedzi, zakłada, że w nazwach katalogów nie ma spacji. Jeśli masz do czynienia ze spacjami, musisz je zacytować, aby różne słowa nie są traktowane jako różne argumenty do mkdirlub cp. Więc twoje polecenie wyglądałoby tak:
mkdir -p "/my directory/name with/spaces"&& cp "my filename with spaces.txt""$_"
Poza tym: zazwyczaj jestem rozczarowany brakiem szczegółów w pytaniach dotyczących poleceń powłoki Bash lub Unixa na stosie przepełnienia stosu, które często wyrzucają skomplikowany i wyjątkowo gęsty jednowarstwowy program, który trudno jest usunąć, jeśli nie jesteś jeszcze czarodziejem uniksowym. Starałem się tu znaleźć skrajne przeciwieństwo i obaj wyjaśniam każdy szczegół składni oraz link do odpowiednich miejsc, aby znaleźć dokumentację na temat tego, jak to działa. Mam nadzieję, że to pomoże przynajmniej niektórym ludziom. Również kredyt, w którym należne: poderwałem to podejście od tej odpowiedzi na duplikat pytania: stackoverflow.com/a/14085147/1709587
Mark Amery
Nigdy wcześniej nie widziałem $ _. do czego to się odnosi? folder użyty w ostatnim poleceniu?
thebunnyrules
9
@ thebunnyrules Ale… ale… jest „jak to działa?” sekcja w mojej odpowiedzi, która dosłownie zawiera wiele akapitów poświęconych właśnie zadanemu pytaniu. Czuje się ignorowany i niekochany. :(
Mark Amery
Przepraszam za to. Masz całkowitą rację. Wiedziałem już wszystko w twojej odpowiedzi, więc po prostu szybko to przejrzałem. Powinienem był to przeczytać uważniej.
thebunnyrules
Wow, naprawdę włożyłeś dużo pracy w tę odpowiedź ... Dzięki za to. Miło było dowiedzieć się o: $ _. Odtąd widzę, jak z niego korzystam. Napisałem skrypt automatyzujący cały proces i umieściłem w tym wątku.
Spróbuj
39
Takie stare pytanie, ale może mogę zaproponować alternatywne rozwiązanie.
Możesz użyć installprogramu do skopiowania pliku i utworzenia ścieżki docelowej „w locie”.
musisz podać także nazwę pliku docelowego , a nie tylko ścieżkę docelową
plik docelowy będzie wykonywalny (przynajmniej, o ile widziałem z moich testów)
Możesz łatwo zmienić numer 2, dodając -mopcję ustawiania uprawnień do pliku docelowego (przykład: -m 664utworzy plik docelowy z uprawnieniami rw-rw-r--, podobnie jak tworzenie nowego pliku za pomocą touch).
Naprawdę nie działało na mój użytek, ale fajna sztuczka! Będę pamiętać.
thebunnyrules
zauważ, że to polecenie tworzy pliki docelowe z uprawnieniami 755( rwxr-xr-x), co prawdopodobnie nie jest pożądane. możesz określić coś innego za pomocą -mprzełącznika, ale nie mogłem znaleźć sposobu na zachowanie uprawnień do plików :(
törzsmókus
19
Funkcja powłoki, która robi to, co chcesz, nazywając ją kopią „zakopaną”, ponieważ wykopuje otwór, w którym znajduje się plik:
@Kalmi, aby uzyskać prawidłową wycenę, chciałbyś również podać ją $2jako argument dirname. Jak mkdir -p "$(dirname "$2")". Bez tego powołując $2się cpma sensu;)
Michael Krelin - haker
3
Zauważ, że ta odpowiedź zakłada, że $ 2 nie jest już katalogiem docelowym, w przeciwnym razie chcesz po prostu „mkdir -p” $ 2 ”&& cp„ $ 1 ”„ $ 2 ”jako ciało funkcji
użytkownik467257
Myślę, że ma to błąd, jak wskazuje @ user467257. Nie sądzę, że można to naprawić, ponieważ 2 USD jest niejednoznaczne między docelowym katalogiem a plikiem docelowym w tym scenariuszu. Zamieściłem alternatywną odpowiedź, która rozwiązuje ten problem.
Bogaty
@Rich, nie zgadzam się, że nie można tego naprawić. Poniższe działa dobrze zarówno dla plików, jak i katalogów: mkdir -p dirname "$2"&& cp -r "$ 1" "$ 2"; Zauważ, że backticks wokół dirname $2się nie pojawiają, ponieważ SO analizuje je jako znaczniki kodu.
dirnameda ci rodzic katalogu docelowego lub pliku docelowego. mkdir -p `nazwa_katalogu ... 'utworzy ten katalog, upewniając się, że po wywołaniu cp -r znajduje się właściwy katalog podstawowy.
Zaletą tego nad-rodziców jest to, że działa w przypadku, gdy ostatnim elementem ścieżki docelowej jest nazwa pliku.
właściwie to wcale nie to samo. jego wymaga dwukrotnego przekazania nazwy pliku (stąd flaga „-t”) i ustawienia bitów wykonania w pliku (stąd przykład „-m”). jego nie powinna być najlepsza odpowiedź, ponieważ tak naprawdę nie odpowiada na pytanie - podczas gdy moja tak.
Spongman,
1
Działa to dla jednego pliku. Weź pod uwagę, że therejest to końcowy plik, a nie ostatni podkatalog.
kvantour
6
Z całym szacunkiem dla powyższych odpowiedzi wolę używać rsync w następujący sposób:
$ rsync -a directory_name /path_where_to_inject_your_directory/
Spróbowałem i sprawdziłem ten wynik: rsync -a bull / some / hoop / ti / doop / ploop WYNIK rsync: mkdir "/ some / hoop / ti / doop / ploop" nie powiodło się: Brak takiego pliku lub katalogu (2) błąd rsync : błąd w pliku IO (kod 11) w main.c (675) [Receiver = 3.1.2]
Jeśli dobrze rozumiem twoją sugestię, proponuję podać pełną ścieżkę do źródła, czyli aka: „$ (pwd) / bull” w moim poleceniu zamiast samej nazwy pliku: bull? Rzecz w tym, że błąd polega na tym, że rsync tworzy katalog docelowy, a nie źródłowy (byk). Wydaje mi się, że rsync używa prostego mkdir, a nie mkdir -p.
thebunnyrules
1
Nawiasem mówiąc, świetne narzędzie, mogę zacząć używać w swoich skryptach. Dziękujemy za polecenie.
thebunnyrules
1
rsync jest bardziej przewidywalny niż cp. Na przykład, jeśli chcę, aby cp /from/somedir /to-dircp zachowywał się inaczej, jeśli /to-dirjuż istnieje: Jeśli /to-diristnieje, to cputworzy /to-dir/some-dir, w przeciwnym razie /from/somedirzostanie umieszczona tylko zawartość /to-dir. Jednak rsynczachowuje się tak samo w przypadku, czyli /to-dir/some-dirbędzie zawsze zostać utworzony.
JoeAC
5
Wystarczy wznowić i dać kompletne rozwiązanie robocze, w jednej linii. Zachowaj ostrożność, jeśli chcesz zmienić nazwę pliku, powinieneś podać sposób na zapewnienie czystej ścieżki katalogu mkdir. $ fdst może być plikiem lub reż. W każdym razie następny kod powinien działać.
Dzięki! Właśnie tego potrzebowałem. W moim przypadku nie wiem, czy miejsce docelowe ma katalog, czy nie i czy katalog istnieje, więc ten kod daje mi katalog nadrzędny, który następnie mogę bezpiecznie utworzyć, jeśli nie istnieje
xbmono
4
Po prostu dodaj następujące elementy do .bashrc, w razie potrzeby popraw je. Działa w Ubuntu.
mkcp(){
test -d "$2"|| mkdir -p "$2"
cp -r "$1""$2"}
Np. Jeśli chcesz skopiować plik „testowy” do katalogu docelowego „d” Użyj,
mkcp test a/b/c/d
mkcp najpierw sprawdzi, czy katalog docelowy istnieje, czy nie, a następnie utworzy go i skopiuje plik źródłowy / katalog.
Gdy inni skomentowali drugą odpowiedź, nie musisz sprawdzać, czy katalog istnieje przed wywołaniem mkdir -p. Odniesie sukces, nawet jeśli już istnieje.
Zgodzić się. W man cp:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
borracciaBlu
3
Napisałem skrypt wsparcia dla cp, zwany CP (uwaga wielkimi literami), który jest przeznaczony właśnie do tego. Skrypt sprawdzi błędy w ścieżce, którą umieściłeś (z wyjątkiem ostatniego, który jest miejscem docelowym), a jeśli wszystko będzie dobrze, wykona krok mkdir -p, aby utworzyć ścieżkę docelową przed rozpoczęciem kopiowania. W tym momencie zwykłe narzędzie cp przejmuje kontrolę i wszelkie przełączniki używane z CP (jak -r, -p, -rpL są przesyłane bezpośrednio do cp). Zanim użyjesz mojego skryptu, musisz zrozumieć kilka rzeczy.
wszystkie informacje tutaj można uzyskać wykonując CP --help. CP - help-all zawiera przełączniki cp.
zwykły cp nie zrobi kopii, jeśli nie znajdzie ścieżki docelowej. Nie masz takiej siatki bezpieczeństwa dla literówek z CP. Miejsce docelowe zostanie utworzone, więc jeśli źle przeliterujesz miejsce docelowe jako / usrr / share / icons lub / usr / share / icon, to właśnie zostanie utworzone.
zwykłe cp ma tendencję do modelowania swojego zachowania na istniejącej ścieżce: cp / a / b / c / d będzie się różnić w zależności od tego, czy d istnieje, czy nie. jeśli d jest istniejącym folderem, cp skopiuje do niego b, tworząc / c / d / b. Jeśli d nie istnieje, b zostanie skopiowane do c i przemianowane na d. Jeśli d istnieje, ale jest plikiem, a b jest plikiem, zostanie zastąpione przez kopię b. Jeśli c nie istnieje, cp nie wykonuje kopii i kończy działanie.
CP nie ma luksusu czerpania wskazówek z istniejących ścieżek, więc musi mieć bardzo twarde wzorce zachowań. CP zakłada, że element, który kopiujesz, jest upuszczany na ścieżkę docelową, a nie sam cel docelowy (inaczej kopia pliku źródłowego / folderu o zmienionej nazwie). Znaczenie:
„CP / a / b / c / d” spowoduje utworzenie / c / d / b, jeśli d jest folderem
„CP / a / b / c / b” spowoduje utworzenie / c / b / b, jeśli b w / c / b jest folderem.
Jeśli oba b i d są plikami: CP / a / b / c / d spowoduje utworzenie / c / d (gdzie d jest kopią b). To samo dotyczy CP / a / b / c / b w tych samych okolicznościach.
To domyślne zachowanie CP można zmienić za pomocą przełącznika „--rename”. W tym przypadku zakłada się, że
„CP - nazwa / a / b / c / d” kopiuje b do / c i zmienia nazwę kopii na d.
Kilka uwag na zakończenie: Podobnie jak w przypadku CP, CP może kopiować wiele przedmiotów na raz, przy założeniu, że ostatnia ścieżka jest na liście docelowej. Może także obsługiwać ścieżki ze spacjami, o ile używasz cudzysłowów.
CP sprawdzi ścieżki, które wstawiłeś i upewni się, że istnieją przed wykonaniem kopii. W trybie ścisłym (dostępnym za pomocą przełącznika --strict) wszystkie kopiowane pliki / foldery muszą istnieć lub kopiowanie nie ma miejsca. W trybie zrelaksowanym (--relaxed) kopiowanie będzie kontynuowane, jeśli przynajmniej jeden z wymienionych elementów istnieje. Tryb zrelaksowany jest domyślny, można go zmienić tymczasowo za pomocą przełączników lub na stałe, ustawiając zmienną easy_going na początku skryptu.
#!/bin/bash#Regular cp works with the assumption that the destination path exists and if it doesn't, it will verify that it's parent directory does.#eg: cp /a/b /c/d will give /c/d/b if folder path /c/d already exists but will give /c/d (where d is renamed copy of b) if /c/d doesn't exists but /c does.#CP works differently, provided that d in /c/d isn't an existing file, it assumes that you're copying item into a folder path called /c/d and will create it if it doesn't exist. so CP /a/b /c/d will always give /c/d/b unless d is an existing file. If you put the --rename switch, it will assume that you're copying into /c and renaming the singl item you're copying from b to d at the destination. Again, if /c doesn't exist, it will be created. So CP --rename /a/b /c/d will give a /c/d and if there already a folder called /c/d, contents of b will be merged into d. #cp+ $source $destination#mkdir -p /foo/bar && cp myfile "$_"
err=0# error count
i=0#item counter, doesn't include destination (starts at 1, ex. item1, item2 etc)
m=0#cp switch counter (starts at 1, switch 1, switch2, etc)
n=1# argument counter (aka the arguments inputed into script, those include both switches and items, aka: $1 $2 $3 $4 $5)
count_s=0
count_i=0
easy_going=true #determines how you deal with bad pathes in your copy, true will allow copy to continue provided one of the items being copied exists, false will exit script for one bad path. this setting can also be changed via the custom switches: --strict and --not-strict
verbal="-v"
help="===============================================================================\
\n CREATIVE COPY SCRIPT (CP) -- written by thebunnyrules\
\n===============================================================================\n
\n This script (CP, note capital letters) is intended to supplement \
\n your system's regular cp command (note uncapped letters). \n
\n Script's function is to check if the destination path exists \
\n before starting the copy. If it doesn't it will be created.\n
\n To make this happen, CP assumes that the item you're copying is \
\n being dropped in the destination path and is not the destination\
\n itself (aka, a renamed copy of the source file/folder). Meaning:\n
\n * \"CP /a/b /c/d\" will result in /c/d/b \
\n * even if you write \"CP /a/b /c/b\", CP will create the path /a/b, \
\n resulting in /c/b/b. \n
\n Of course, if /c/b or /c/d are existing files and /a/b is also a\
\n file, the existing destination file will simply be overwritten. \
\n This behavior can be changed with the \"--rename\" switch. In this\
\n case, it's assumed that \"CP --rename /a/b /c/d\" is copying b into /c \
\n and renaming the copy to d.\n
\n===============================================================================\
\n CP specific help: Switches and their Usages \
\n===============================================================================\n
\
\n --rename\tSee above. Ignored if copying more than one item. \n
\n --quiet\tCP is verbose by default. This quiets it.\n
\n --strict\tIf one+ of your files was not found, CP exits if\
\n\t\tyou use --rename switch with multiple items, CP \
\n\t\texits.\n
\n --relaxed\tIgnores bad paths unless they're all bad but warns\
\n\t\tyou about them. Ignores in-appropriate rename switch\
\n\t\twithout exiting. This is default behavior. You can \
\n\t\tmake strict the default behavior by editing the \
\n\t\tCP script and setting: \n
\n\t\teasy_going=false.\n
\n --help-all\tShows help specific to cp (in addition to CP)."
cp_hlp="\n\nRegular cp command's switches will still work when using CP.\
\nHere is the help out of the original cp command... \
\n\n===============================================================================\
\n cp specific help: \
\n===============================================================================\n"
outro1="\n******************************************************************************\
\n******************************************************************************\
\n******************************************************************************\
\n USE THIS SCRIPT WITH CARE, TYPOS WILL GIVE YOU PROBLEMS...\
\n******************************************************************************\
\n******************************* HIT q TO EXIT ********************************\
\n******************************************************************************"#count and classify arguments that were inputed into script, output help message if neededwhile true;doeval input="\$$n"
in_=${input::1}if[-z "$input"-a $n =1];then input="--help";fiif["$input"="-h"-o "$input"="--help"-o "$input"="-?"-o "$input"="--help-all"];thenif["$input"="--help-all"];then
echo -e "$help"$cp_hlp >/tmp/cp.hlp
cp --help >>/tmp/cp.hlp
echo -e "$outro1">>/tmp/cp.hlp
cat /tmp/cp.hlp|less
cat /tmp/cp.hlp
rm /tmp/cp.hlp
else
echo -e "$help""$outro1"|less
echo -e "$help""$outro1"fi
exit
fiif[-z "$input"];then
count_i=$(expr $count_i -1)# remember, last item is destination and it's not included in coundbreakelif["$in_"="-"];then
count_s=$(expr $count_s +1)else
count_i=$(expr $count_i +1)fi
n=$(expr $n +1)done#error condition: no items to copy or no destinationif[ $count_i -lt 0];then
echo "Error: You haven't listed any items for copying. Exiting."# you didn't put any items for copyingelif[ $count_i -lt 1];then
echo "Error: Copying usually involves a destination. Exiting."# you put one item and no destinationfi#reset the counter and grab content of arguments, aka: switches and item paths
n=1while true;doeval input="\$$n"#input=$1,$2,$3,etc...
in_=${input::1}#first letter of $inputif["$in_"="-"];thenif["$input"="--rename"];then
rename=true #my custom switcheselif["$input"="--strict"];then
easy_going=false #exit script if even one of the non-destinations item is not foundelif["$input"="--relaxed"];then
easy_going=true #continue script if at least one of the non-destination items is foundelif["$input"="--quiet"];then
verbal=""else#m=$(expr $m + 1);eval switch$m="$input" #input is a switch, if it's not one of the above, assume it belongs to cp.
switch_list="$switch_list \"$input\""fielif![-z "$input"];then#if it's not a switch and input is not empty, it's a path
i=$(expr $i +1)if[!-f "$input"-a !-d "$input"-a "$i"-le "$count_i"];then
err=$(expr $err +1); error_list="$error_list\npath does not exit: \"b\""elseif["$i"-le "$count_i"];theneval item$i="$input"
item_list="$item_list \"$input\""else
destination="$input"#destination is last items enteredfifielse
i=0
m=0
n=1breakfi
n=$(expr $n +1)done#error condition: some or all item(s) being copied don't exist. easy_going: continue if at least one item exists, warn about rest, not easy_going: exit.#echo "err=$err count_i=$count_i"if["$easy_going"!= true -a $err -gt 0-a $err != $count_i ];then
echo "Some of the paths you entered are incorrect. Script is running in strict mode and will therefore exit."
echo -e "Bad Paths: $err $error_list"
exit
fiif[ $err = $count_i ];then
echo "ALL THE PATHS you have entered are incorrect! Exiting."
echo -e "Bad Paths: $err $error_list"fi#one item to one destination:#------------------------------#assumes that destination is folder, it does't exist, it will create it. (so copying /a/b/c/d/firefox to /e/f/firefox will result in /e/f/firefox/firefox#if -rename switch is given, will assume that the top element of destination path is the new name for the the item being given.#multi-item to single destination:#------------------------------#assumes destination is a folder, gives error if it exists and it's a file. -rename switch will be ignored.#ERROR CONDITIONS: # - multiple items being sent to a destination and it's a file.# - if -rename switch was given and multiple items are being copied, rename switch will be ignored (easy_going). if not easy_going, exit.# - rename option but source is folder, destination is file, exit.# - rename option but source is file and destination is folder. easy_going: option ignored.if[-f "$destination"];thenif[ $count_i -gt 1];then
echo "Error: You've selected a single file as a destination and are copying multiple items to it. Exiting."; exit
elif[-d "$item1"];then
echo "Error: Your destination is a file but your source is a folder. Exiting."; exit
fifiif["$rename"= true ];thenif[ $count_i -gt 1];thenif[ $easy_going = true ];then
echo "Warning: you choose the rename option but are copying multiple items. Ignoring Rename option. Continuing."else
echo "Error: you choose the rename option but are copying multiple items. Script running in strict mode. Exiting."; exit
fielif[-d "$destination"-a -f "$item1"];then
echo -n "Warning: you choose the rename option but source is a file and destination is a folder with the same name. "if[ $easy_going = true ];then
echo "Ignoring Rename option. Continuing."else
echo "Script running in strict mode. Exiting."; exit
fielse
dest_jr=$(dirname "$destination")if[-d "$destination"];then item_list="$item1/*";fi
mkdir -p "$dest_jr"fielse
mkdir -p "$destination"fieval cp $switch_list $verbal $item_list "$destination"
cp_err="$?"if["$cp_err"!=0];then
echo -e "Something went wrong with the copy operation. \nExit Status: $cp_err"else
echo "Copy operation exited with no errors."fi
exit
To może przesada, ale całkiem wydajne, działa zgodnie z oczekiwaniami, dziękuję dobry panie.
Xedret
2
cp ma wiele zastosowań:
$ cp --help
Usage: cp [OPTION]...[-T] SOURCE DEST
or: cp [OPTION]... SOURCE... DIRECTORY
or: cp [OPTION]...-t DIRECTORY SOURCE...Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
@ Odpowiedź AndyRossa działa dla
cp SOURCE DEST
styl cp, ale robi coś złego, jeśli używasz
cp SOURCE... DIRECTORY/
styl cp.
Myślę, że „DEST” jest niejednoznaczny bez końcowego ukośnika w tym użyciu (tj. Gdzie katalog docelowy jeszcze nie istnieje), i być może dlatego cpnigdy nie dodał do tego opcji.
Oto moja wersja tej funkcji, która wymusza ukośnik końcowy w katalogu docelowym:
Jak sugerują wyżej help_asap i spongeman, możesz użyć polecenia „install”, aby skopiować pliki do istniejących katalogów lub utworzyć nowe katalogi docelowe, jeśli jeszcze nie istnieją.
Opcja 1
install -D filename some/deep/directory/filename
kopiuje plik do nowego lub istniejącego katalogu i daje domyślne uprawnienia do nazwy pliku 755
Opcja 2
install -D filename -m640 some/deep/directory/filename
zgodnie z Opcją 1, ale daje uprawnienia do nazwy pliku 640.
Opcja 3
install -D filename -m640 -t some/deep/directory/
zgodnie z Opcją 2, ale wskazuje nazwę pliku w katalogu docelowym, więc nazwa pliku nie musi być zapisywana zarówno w źródle, jak i celu.
Opcja 4
install -D filena* -m640 -t some/deep/directory/
zgodnie z Opcją 3, ale używa symboli wieloznacznych dla wielu plików.
Działa ładnie w Ubuntu i łączy dwa kroki (tworzenie katalogu, a następnie kopiowanie plików) w jednym kroku.
Jest bardzo późno, ale może pomóc gdzieś nowicjuszowi. Jeśli potrzebujesz „automatycznie” tworzyć foldery, najlepszym przyjacielem powinien być rsync. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
cp
(na co odpowiedział Paul Whipp), ale nie jest ona tak ogólna, jak wymagała PO. Może kopiowaća/foo/bar/file
do,b/foo/bar/file
ale nie może kopiowaćfile
dob/foo/bar/file
. (tzn. działa tylko w celu utworzenia katalogów nadrzędnych, które już istniały w przypadku pierwszego pliku, ale nie można utworzyć dowolnych katalogów)Odpowiedzi:
(nie ma takiej opcji
cp
).źródło
test -d
:mkdir -p
nadal działa, nawet jeśli katalog już istnieje.mkdir
jest wbudowany w BusyBox;)$d
jest zmienną, która prawdopodobnie zawiera dany katalog. Chodzi mi o to, że jeśli musisz powtórzyć trzy razy, prawdopodobnie najpierw przypisasz go do zmiennej.Jeśli oba poniższe warunki są prawdziwe:
cp
(a nie na przykład wersji Mac) inastępnie można to zrobić z
--parents
flagącp
. Ze strony informacyjnej (można zobaczyć na stronie http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation lub za pomocąinfo cp
lubman cp
):Przykład:
źródło
macports
, możesz zainstalować coreutils i jegogcp
.Krótka odpowiedź
Aby skopiować
myfile.txt
do/foo/bar/myfile.txt
, użyj:Jak to działa?
Składa się na to kilka elementów, więc krok po kroku omówię całą składnię.
Narzędzie mkdir , określone w standardzie POSIX , tworzy katalogi.
-p
Argument za docs, spowoduje mkdir doco oznacza, że podczas rozmowy
mkdir -p /foo/bar
, mkdir tworzy/foo
i/foo/bar
jeśli/foo
jeszcze nie istnieje. (Bez-p
tego spowoduje zgłoszenie błędu.&&
Operator lista, co zostało udokumentowane w standardzie POSIX (lub instrukcji Bash jeśli wolisz), ma ten skutek, żecp myfile.txt $_
tylko jeśli zostanie wykonanymkdir -p /foo/bar
pomyślnie. Oznacza to, żecp
polecenie nie spróbuje wykonać, jeślimkdir
zakończy się niepowodzeniem z jednego z wielu powodów, dla których może się nie powieść .Wreszcie,
$_
drugi argument podajemy jakocp
„specjalny parametr”, który może być przydatny, aby uniknąć powtarzania długich argumentów (takich jak ścieżki plików) bez konieczności przechowywania ich w zmiennej. Zgodnie z instrukcją Bash :W tym przypadku do
/foo/bar
tego przeszliśmymkdir
. Tak więccp
polecenie rozwija się docp myfile.txt /foo/bar
, który kopiujemyfile.txt
do nowo utworzonego/foo/bar
katalogu.Zauważ, że nie
$_
jest to część standardu POSIX , więc teoretycznie wariant Uniksa może mieć powłokę, która nie obsługuje tej konstrukcji. Jednak nie znam żadnych nowoczesnych powłok, które nie obsługują$_
; Z pewnością Bash, Dash i Zsh.Ostatnia uwaga: polecenie, które wydałem na początku tej odpowiedzi, zakłada, że w nazwach katalogów nie ma spacji. Jeśli masz do czynienia ze spacjami, musisz je zacytować, aby różne słowa nie są traktowane jako różne argumenty do
mkdir
lubcp
. Więc twoje polecenie wyglądałoby tak:źródło
Takie stare pytanie, ale może mogę zaproponować alternatywne rozwiązanie.
Możesz użyć
install
programu do skopiowania pliku i utworzenia ścieżki docelowej „w locie”.Należy jednak wziąć pod uwagę kilka aspektów:
Możesz łatwo zmienić numer 2, dodając
-m
opcję ustawiania uprawnień do pliku docelowego (przykład:-m 664
utworzy plik docelowy z uprawnieniamirw-rw-r--
, podobnie jak tworzenie nowego pliku za pomocątouch
).A oto bezwstydny link do odpowiedzi, którą zainspirowałam =)
źródło
755
(rwxr-xr-x
), co prawdopodobnie nie jest pożądane. możesz określić coś innego za pomocą-m
przełącznika, ale nie mogłem znaleźć sposobu na zachowanie uprawnień do plików :(Funkcja powłoki, która robi to, co chcesz, nazywając ją kopią „zakopaną”, ponieważ wykopuje otwór, w którym znajduje się plik:
źródło
dirname $2
zbyt$2
jako argumentdirname
. Jakmkdir -p "$(dirname "$2")"
. Bez tego powołując$2
sięcp
ma sensu;)dirname "$2"
&& cp -r "$ 1" "$ 2"; Zauważ, że backticks wokółdirname $2
się nie pojawiają, ponieważ SO analizuje je jako znaczniki kodu.Oto jeden ze sposobów, aby to zrobić:
dirname
da ci rodzic katalogu docelowego lub pliku docelowego. mkdir -p `nazwa_katalogu ... 'utworzy ten katalog, upewniając się, że po wywołaniu cp -r znajduje się właściwy katalog podstawowy.Zaletą tego nad-rodziców jest to, że działa w przypadku, gdy ostatnim elementem ścieżki docelowej jest nazwa pliku.
I będzie działać na OS X.
źródło
install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there
źródło
there
jest to końcowy plik, a nie ostatni podkatalog.Z całym szacunkiem dla powyższych odpowiedzi wolę używać rsync w następujący sposób:
przykład:
źródło
rsync
jest bardziej przewidywalny niżcp
. Na przykład, jeśli chcę, abycp /from/somedir /to-dir
cp zachowywał się inaczej, jeśli/to-dir
już istnieje: Jeśli/to-dir
istnieje, tocp
utworzy/to-dir/some-dir
, w przeciwnym razie/from/somedir
zostanie umieszczona tylko zawartość/to-dir
. Jednakrsync
zachowuje się tak samo w przypadku, czyli/to-dir/some-dir
będzie zawsze zostać utworzony.Wystarczy wznowić i dać kompletne rozwiązanie robocze, w jednej linii. Zachowaj ostrożność, jeśli chcesz zmienić nazwę pliku, powinieneś podać sposób na zapewnienie czystej ścieżki katalogu mkdir. $ fdst może być plikiem lub reż. W każdym razie następny kod powinien działać.
lub specyficzne dla bash
źródło
Po prostu dodaj następujące elementy do .bashrc, w razie potrzeby popraw je. Działa w Ubuntu.
Np. Jeśli chcesz skopiować plik „testowy” do katalogu docelowego „d” Użyj,
mkcp najpierw sprawdzi, czy katalog docelowy istnieje, czy nie, a następnie utworzy go i skopiuje plik źródłowy / katalog.
źródło
mkdir -p
. Odniesie sukces, nawet jeśli już istnieje.To mi wystarcza
źródło
man cp
:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
Napisałem skrypt wsparcia dla cp, zwany CP (uwaga wielkimi literami), który jest przeznaczony właśnie do tego. Skrypt sprawdzi błędy w ścieżce, którą umieściłeś (z wyjątkiem ostatniego, który jest miejscem docelowym), a jeśli wszystko będzie dobrze, wykona krok mkdir -p, aby utworzyć ścieżkę docelową przed rozpoczęciem kopiowania. W tym momencie zwykłe narzędzie cp przejmuje kontrolę i wszelkie przełączniki używane z CP (jak -r, -p, -rpL są przesyłane bezpośrednio do cp). Zanim użyjesz mojego skryptu, musisz zrozumieć kilka rzeczy.
CP nie ma luksusu czerpania wskazówek z istniejących ścieżek, więc musi mieć bardzo twarde wzorce zachowań. CP zakłada, że element, który kopiujesz, jest upuszczany na ścieżkę docelową, a nie sam cel docelowy (inaczej kopia pliku źródłowego / folderu o zmienionej nazwie). Znaczenie:
To domyślne zachowanie CP można zmienić za pomocą przełącznika „--rename”. W tym przypadku zakłada się, że
Kilka uwag na zakończenie: Podobnie jak w przypadku CP, CP może kopiować wiele przedmiotów na raz, przy założeniu, że ostatnia ścieżka jest na liście docelowej. Może także obsługiwać ścieżki ze spacjami, o ile używasz cudzysłowów.
CP sprawdzi ścieżki, które wstawiłeś i upewni się, że istnieją przed wykonaniem kopii. W trybie ścisłym (dostępnym za pomocą przełącznika --strict) wszystkie kopiowane pliki / foldery muszą istnieć lub kopiowanie nie ma miejsca. W trybie zrelaksowanym (--relaxed) kopiowanie będzie kontynuowane, jeśli przynajmniej jeden z wymienionych elementów istnieje. Tryb zrelaksowany jest domyślny, można go zmienić tymczasowo za pomocą przełączników lub na stałe, ustawiając zmienną easy_going na początku skryptu.
Oto jak go zainstalować:
W terminalu innym niż root wykonaj:
W gedit wklej narzędzie CP i zapisz:
źródło
cp
ma wiele zastosowań:@ Odpowiedź AndyRossa działa dla
styl
cp
, ale robi coś złego, jeśli używaszstyl
cp
.Myślę, że „DEST” jest niejednoznaczny bez końcowego ukośnika w tym użyciu (tj. Gdzie katalog docelowy jeszcze nie istnieje), i być może dlatego
cp
nigdy nie dodał do tego opcji.Oto moja wersja tej funkcji, która wymusza ukośnik końcowy w katalogu docelowym:
źródło
Właśnie miałem ten sam problem. Moje podejście polegało na tarowaniu plików do archiwum w następujący sposób:
tar cf your_archive.tar file1 /path/to/file2 path/to/even/deeper/file3
tar automatycznie przechowuje pliki w odpowiedniej strukturze w archiwum. Jeśli uciekniesz
tar xf your_archive.tar
pliki są wyodrębniane do żądanej struktury katalogów.
źródło
Jak sugerują wyżej help_asap i spongeman, możesz użyć polecenia „install”, aby skopiować pliki do istniejących katalogów lub utworzyć nowe katalogi docelowe, jeśli jeszcze nie istnieją.
Opcja 1
install -D filename some/deep/directory/filename
kopiuje plik do nowego lub istniejącego katalogu i daje domyślne uprawnienia do nazwy pliku 755
Opcja 2
install -D filename -m640 some/deep/directory/filename
zgodnie z Opcją 1, ale daje uprawnienia do nazwy pliku 640.
Opcja 3
install -D filename -m640 -t some/deep/directory/
zgodnie z Opcją 2, ale wskazuje nazwę pliku w katalogu docelowym, więc nazwa pliku nie musi być zapisywana zarówno w źródle, jak i celu.
Opcja 4
install -D filena* -m640 -t some/deep/directory/
zgodnie z Opcją 3, ale używa symboli wieloznacznych dla wielu plików.
Działa ładnie w Ubuntu i łączy dwa kroki (tworzenie katalogu, a następnie kopiowanie plików) w jednym kroku.
źródło
Jest bardzo późno, ale może pomóc gdzieś nowicjuszowi. Jeśli potrzebujesz „automatycznie” tworzyć foldery, najlepszym przyjacielem powinien być rsync. rsync / path / to / sourcefile / path / to / tragetdir / thatdoestexist /
źródło
To może zadziałać, jeśli masz odpowiedni rodzaj
rsync
.źródło
Skopiuj ze źródła do nieistniejącej ścieżki
UWAGA: to polecenie kopiuje wszystkie pliki
cp –r
do kopiowania wszystkich folderów i ich zawartości$_
działa jako miejsce docelowe utworzone w ostatnim poleceniuźródło
Prosty
powinien załatwić sprawę.
źródło
Powiedzmy, że robisz coś takiego
gdzie A / B / C / D to katalogi, które jeszcze nie istnieją
Możliwe rozwiązanie jest następujące
mam nadzieję, że to pomaga!
źródło