Jawaban yang diterima salah (ada opsi untuk cp). Lihat jawaban kedua oleh Paul Whipp.
Ronenz
1
@Ronenz, saya setuju bahwa ada opsi yang layak disebutkan dalam GNU cp(seperti yang dijawab oleh Paul Whipp), tetapi ini tidak umum seperti yang diminta OP. Hal ini dapat menyalin a/foo/bar/fileke b/foo/bar/filetetapi tidak dapat menyalin fileke b/foo/bar/file. (Yaitu hanya berfungsi untuk membuat direktori induk yang sudah ada dalam kasus file pertama, tetapi tidak dapat membuat direktori sewenang-wenang)
Sudo Bash
Itu terlihat seperti permintaan fitur yang bagus untuk cp. Apakah ada kemungkinan kita bisa mendapatkan saklar baris perintah dalam waktu dekat?
Saya rasa Anda tidak perlu test -d: mkdir -pmasih berhasil walaupun direktori sudah ada.
ephemient
Ups, benar. Tapi kemudian, tes mungkin builtin bash (terutama jika ditulis sebagai [[-d "$ d"]]) dan mkdir tidak bisa ;-)
Michael Krelin - hacker
1
mkdiradalah builtin di BusyBox;)
ephemient
7
@holms, $dadalah variabel yang mungkin berisi direktori yang dimaksud. Maksud saya, jika Anda harus mengulanginya tiga kali, Anda cenderung menugaskannya ke variabel terlebih dahulu.
Michael Krelin - hacker
237
Jika kedua hal berikut ini benar:
Anda menggunakan versi GNU dari cp (dan bukan, misalnya, versi Mac), dan
Anda menyalin dari beberapa struktur direktori yang ada dan Anda hanya perlu membuatnya kembali
--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.
Contoh:
/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
Ini tidak berfungsi pada Mac OS X, jadi saya kira itu spesifik Linux.
olt
7
Saya akan mengatakan gnu-spesifik. Jika sudah, macportsAnda dapat menginstal coreutils dan gcp.
Michael Krelin - hacker
16
Sobat, linux memiliki segalanya
Ziggy
19
Saya merasa ini adalah jawaban untuk pertanyaan yang sedikit berbeda, meskipun itu adalah jawaban yang saya cari (dan karena itu yang saya pilih). Saya kira ini solusinya dengan asumsi Anda ingin direktori induk tujuan sama dengan direktori induk asal, yang mungkin merupakan kasus penggunaan yang menarik bagi kebanyakan orang.
David Winiecki
7
Ini mengasumsikan 'bar' direktori sudah ada, tetapi pertanyaan asli menyiratkan bagaimana membuat 'bar' secara otomatis ketika disediakan sebagai tujuan dan itu belum ada. Jawabannya diberikan oleh @ MichaelKrelin-hacker.
thdoan
69
Jawaban singkat
Untuk menyalin myfile.txtke /foo/bar/myfile.txt, gunakan:
mkdir -p /foo/bar && cp myfile.txt $_
Bagaimana cara kerjanya?
Ada beberapa komponen untuk ini, jadi saya akan membahas semua langkah demi langkah sintaksis.
artinya ketika memanggil mkdir -p /foo/bar, mkdir akan membuat /foodan/foo/bar jika /foobelum ada. (Tanpa -p, itu malah akan menimbulkan kesalahan.
The &&Operator daftar, seperti yang didokumentasikan dalam standar POSIX (atau pengguna Bash jika Anda suka), memiliki efek yang cp myfile.txt $_hanya dijalankan jika mkdir -p /foo/barmengeksekusi berhasil. Ini berarti cpperintah tidak akan mencoba untuk mengeksekusi jika mkdirgagal karena salah satu dari banyak alasan itu mungkin gagal .
Akhirnya, $_kita cpmenganggap argumen kedua adalah "parameter khusus" yang berguna untuk menghindari pengulangan argumen panjang (seperti path file) tanpa harus menyimpannya dalam variabel. Per manual Bash , itu:
memperluas argumen terakhir ke perintah sebelumnya
Dalam hal ini, itulah yang /foo/barkami berikan mkdir. Jadi cpperintah diperluas ke cp myfile.txt /foo/bar, yang menyalin myfile.txtke /foo/bardirektori yang baru dibuat .
Perhatikan bahwa $_ini bukan bagian dari standar POSIX , sehingga secara teoritis varian Unix mungkin memiliki shell yang tidak mendukung konstruk ini. Namun, saya tidak tahu adanya kerang modern yang tidak mendukung $_; tentu Bash, Dash, dan zsh semua lakukan.
Catatan terakhir: perintah yang saya berikan di awal jawaban ini mengasumsikan bahwa nama direktori Anda tidak memiliki spasi. Jika Anda berurusan dengan nama dengan spasi, Anda harus mengutipnya sehingga kata-kata yang berbeda tidak diperlakukan sebagai argumen berbeda dengan mkdiratau cp. Jadi perintah Anda sebenarnya akan terlihat seperti:
mkdir -p "/my directory/name with/spaces"&& cp "my filename with spaces.txt""$_"
Selain itu: Saya biasanya kecewa dengan kurangnya detail dalam pertanyaan tentang perintah shell Bash atau Unix di Stack Overflow, yang sering mengeluarkan satu-liner yang rumit dan sangat padat yang sulit dihapus jika Anda belum menjadi penyihir Unix. Saya sudah mencoba untuk mencoba ekstrim yang berlawanan di sini dan keduanya menjelaskan setiap detail sintaks dan tautan ke tempat yang tepat untuk menemukan dokumentasi tentang bagaimana hal ini bekerja. Saya harap ini membantu setidaknya beberapa orang. Juga, kredit yang jatuh tempo: Saya menandai pendekatan ini dari jawaban ini menjadi pertanyaan rangkap: stackoverflow.com/a/14085147/1709587
Mark Amery
Saya belum pernah melihat $ _ sebelumnya. apa yang dimaksud folder yang digunakan dalam perintah terakhir?
thebunnyrules
9
@thebunnyrules Tapi ... tapi ... ada "Bagaimana cara kerjanya?" bagian dalam jawaban saya yang secara harfiah berisi beberapa paragraf khusus yang ditujukan untuk pertanyaan yang baru saja Anda tanyakan. Rasanya diabaikan dan tidak dicintai. :(
Mark Amery
Maaf soal itu. Anda benar sekali. Saya sudah tahu semua hal lain dalam jawaban Anda, jadi saya segera memindai semua itu. Seharusnya saya membacanya lebih hati-hati.
thebunnyrules
Wow, Anda benar-benar memasukkan banyak pekerjaan ke dalam jawaban itu ... Terima kasih untuk itu. Sangat menyenangkan untuk belajar tentang: $ _. Saya bisa melihat diri saya menggunakannya sedikit mulai sekarang. Saya menulis naskah untuk mengotomatiskan seluruh proses dan memasang di utas ini.
Cobalah
39
Pertanyaan yang lama, tapi mungkin saya bisa mengusulkan solusi alternatif.
Anda dapat menggunakan installprogram ini untuk menyalin file Anda dan membuat jalur tujuan "on the fly".
Namun ada beberapa aspek yang perlu dipertimbangkan:
Anda harus menentukan juga nama file tujuan , bukan hanya jalur tujuan
file tujuan akan dapat dieksekusi (setidaknya, sejauh yang saya lihat dari tes saya)
Anda dapat dengan mudah mengubah # 2 dengan menambahkan -mopsi untuk mengatur izin pada file tujuan (contoh: -m 664akan membuat file tujuan dengan izin rw-rw-r--, seperti halnya membuat file baru dengan touch).
Tidak benar-benar berfungsi untuk penggunaan saya tetapi trik keren! Saya akan mengingatnya.
thebunnyrules
perhatikan bahwa perintah ini membuat file tujuan dengan 755( rwxr-xr-x) izin, yang mungkin tidak diinginkan. Anda dapat menentukan sesuatu yang lain dengan -msaklar, tetapi saya tidak dapat menemukan cara untuk hanya menyimpan izin file :(
törzsmókus
19
Fungsi Shell yang melakukan apa yang Anda inginkan, menyebutnya salinan "mengubur" karena menggali lubang untuk tempat tinggal file:
Anda harus memiliki tanda kutip di sekitar dirname $2juga
Tarnay Kálmán
4
@ Kalmi, untuk kutipan yang tepat Anda juga ingin mengutip $2sebagai argumen dirname. Seperti mkdir -p "$(dirname "$2")". Tanpa ini mengutip $2di cptidak berguna;)
Michael Krelin - hacker
3
Perhatikan bahwa jawaban ini menganggap $ 2 belum menjadi direktori target, jika tidak Anda hanya ingin "mkdir -p" $ 2 "&& cp" $ 1 "" $ 2 "sebagai badan fungsi
user467257
Saya pikir ini memiliki bug, seperti yang ditunjukkan oleh @ user467257. Saya tidak berpikir ini bisa diperbaiki, karena $ 2 ambigu antara direktori target dan file target dalam skenario ini. Saya telah memposting jawaban alternatif yang membahas hal ini.
Kaya
@ Rich, saya tidak setuju bahwa ini tidak dapat diperbaiki. Berikut ini berfungsi dengan baik untuk file dan direktori: mkdir -p dirname "$2"&& cp -r "$ 1" "$ 2"; Perhatikan bahwa backtick di sekitar dirname $2tidak muncul karena SO mem-parsing mereka sebagai penanda kode.
dirnameakan memberi Anda induk dari direktori tujuan atau file. mkdir -p `dirname ...` kemudian akan membuat direktori itu memastikan bahwa ketika Anda memanggil cp -r direktori basis yang benar sudah ada.
Keuntungan over - orang tua ini adalah bahwa ia bekerja untuk kasus di mana elemen terakhir di jalur tujuan adalah nama file.
sebenarnya, itu tidak sama sekali. itu mengharuskan Anda untuk melewatkan nama file dua kali (maka bendera '-t') dan itu menetapkan bit eksekusi pada file (maka contoh '-m'). seharusnya tidak menjadi jawaban teratas, karena itu tidak benar-benar menjawab pertanyaan - sedangkan saya menjawab.
Spongman
1
Ini berfungsi untuk satu file. Hanya memperhitungkan bahwa itu thereadalah file terakhir dan bukan subdirektori akhir.
kvantour
6
dengan segala hormat saya untuk jawaban di atas, saya lebih suka menggunakan rsync sebagai berikut:
$ rsync -a directory_name /path_where_to_inject_your_directory/
Saya mencobanya dan menuju hasil ini: rsync -a bull / some / hoop / ti / doop / ploop HASIL rsync: mkdir "/ some / hoop / ti / doop / ploop" gagal: Tidak ada file atau direktori (2) kesalahan rsync : kesalahan dalam file IO (kode 11) di main.c (675) [Receiver = 3.1.2]
Jika saya memahami saran Anda dengan benar, Anda mengusulkan agar saya menentukan path lengkap ke sumber alias gunakan: "$ (pwd) / bull" di perintah saya alih-alih hanya nama file: bull? Masalahnya, kesalahannya adalah dengan rsync membuat tujuan tujuan, bukan sumber (bull). Menurut saya rsync menggunakan mkdir sederhana dan bukan mkdir -p.
thebunnyrules
1
Utilitas hebat, saya mungkin mulai menggunakan dalam skrip saya. Terima kasih telah merekomendasikannya.
thebunnyrules
1
rsync lebih dapat diprediksi daripada cp. Misalnya, jika saya ingin cp /from/somedir /to-dirmaka cp berperilaku berbeda jika /to-dirsudah ada: Jika /to-dirada, maka cpakan membuat /to-dir/some-dir, jika tidak, hanya konten /from/somedirditempatkan ke /to-dir. Namun, rsyncberperilaku sama dalam hal, yaitu, /to-dir/some-dirakan selalu dibuat.
JoeAC
5
Hanya untuk melanjutkan dan memberikan solusi kerja yang lengkap, dalam satu baris. Hati-hati jika Anda ingin mengganti nama file Anda, Anda harus memasukkan cara untuk memberikan path dir bersih ke mkdir. $ fdst dapat berupa file atau dir. Kode selanjutnya harus berfungsi dalam hal apa pun.
Terima kasih! Inilah yang saya butuhkan. Dalam kasus saya, saya tidak tahu apakah tujuan memiliki direktori atau tidak dan apakah direktori ada atau tidak sehingga kode ini memberi saya direktori induk yang kemudian saya dapat membuatnya dengan aman jika tidak ada
xbmono
4
Cukup tambahkan berikut ini di .bashrc Anda, tweak jika Anda perlu. Bekerja di Ubuntu.
mkcp(){
test -d "$2"|| mkdir -p "$2"
cp -r "$1""$2"}
Misalnya Jika Anda ingin menyalin file 'test' ke direktori tujuan 'd' Gunakan,
mkcp test a/b/c/d
mkcp pertama-tama akan memeriksa apakah direktori tujuan ada atau tidak, jika tidak maka buatlah dan salin file sumber / direktori.
Seperti orang lain mengomentari jawaban lain, Anda tidak perlu menguji apakah direktori ada sebelum memanggil mkdir -p. Itu akan berhasil bahkan jika sudah ada.
Setuju. Dalam man cp:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
borracciaBlu
3
Saya menulis skrip dukungan untuk cp, yang disebut CP (huruf besar) yang dimaksudkan untuk melakukan hal ini. Script akan memeriksa kesalahan di jalur yang Anda masukkan (kecuali yang terakhir yang menjadi tujuan) dan jika semuanya baik-baik saja, ia akan melakukan langkah mkdir -p untuk membuat jalur tujuan sebelum memulai penyalinan. Pada titik ini utilitas cp reguler mengambil alih dan setiap sakelar yang Anda gunakan dengan CP (seperti -r, -p, -rpL akan disalurkan langsung ke cp). Sebelum Anda menggunakan skrip saya, ada beberapa hal yang perlu Anda pahami.
semua info di sini dapat diakses dengan melakukan CP --help. CP --membantu semua sakelar cp yang disertakan.
cp biasa tidak akan melakukan salinan jika tidak menemukan jalur tujuan. Anda tidak memiliki jaring pengaman untuk kesalahan ketik dengan CP. Tujuan Anda akan dibuat, jadi jika Anda salah mengeja tujuan Anda sebagai / usrr / share / ikon atau / usr / share / ikon dengan baik itulah yang akan dibuat.
regular cp cenderung memodelkan perilaku di jalur yang ada: cp / a / b / c / d akan bervariasi pada apakah d ada atau tidak. jika d adalah folder yang ada, cp akan menyalin b ke dalamnya, membuat / c / d / b. Jika d tidak ada, b akan disalin ke c dan diganti namanya menjadi d. Jika d ada tetapi merupakan file dan b adalah file, itu akan ditimpa oleh salinan b. Jika c tidak ada, cp tidak melakukan penyalinan dan keluar.
CP tidak memiliki kemewahan untuk mengambil isyarat dari jalur yang ada, sehingga harus memiliki beberapa pola perilaku yang sangat tegas. CP mengasumsikan bahwa item yang Anda salin dijatuhkan di jalur tujuan dan bukan tujuan itu sendiri (alias, salinan yang diubah namanya dari file sumber / folder). Berarti:
"CP / a / b / c / d" akan menghasilkan / c / d / b jika d adalah folder
"CP / a / b / c / b" akan menghasilkan / c / b / b jika b in / c / b adalah folder.
Jika b dan d adalah file: CP / a / b / c / d akan menghasilkan / c / d (di mana d adalah salinan b). Sama untuk CP / a / b / c / b dalam kondisi yang sama.
Perilaku CP default ini dapat diubah dengan sakelar "--rename". Dalam hal ini, diasumsikan demikian
"CP --rename / a / b / c / d" menyalin b ke / c dan mengganti nama salinan menjadi d.
Beberapa catatan penutup: Seperti dengan cp, CP dapat menyalin beberapa item sekaligus dengan jalur terakhir yang didaftarkan dianggap sebagai tujuan. Itu juga bisa menangani jalur dengan spasi selama Anda menggunakan tanda kutip.
CP akan memeriksa jalur yang Anda letakkan dan memastikan keberadaannya sebelum melakukan penyalinan. Dalam mode ketat (tersedia melalui saklar --strict), semua file / folder yang disalin harus ada atau tidak ada salinan yang terjadi. Dalam mode santai (--relaxed), penyalinan akan dilanjutkan jika setidaknya ada satu item yang Anda daftarkan. Mode santai adalah default, Anda dapat mengubah mode sementara melalui sakelar atau secara permanen dengan mengatur variabel easy_going di awal skrip.
#!/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
Ini mungkin kerja keras, tapi cukup efisien, bekerja seperti yang diharapkan, terima kasih tuan yang baik.
Xedret
2
cp memiliki beberapa penggunaan:
$ 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.
@ AndyRoss menjawab bekerja untuk
cp SOURCE DEST
gaya cp, tetapi melakukan hal yang salah jika Anda menggunakan
cp SOURCE... DIRECTORY/
gaya cp.
Saya pikir "DEST" tidak jelas tanpa garis miring dalam penggunaan ini (yaitu di mana direktori target belum ada), yang mungkin mengapa cptidak pernah menambahkan opsi untuk ini.
Jadi, inilah versi saya dari fungsi ini yang memberlakukan garis miring pada direktori tujuan:
Seperti yang disarankan di atas oleh help_asap dan spongeman, Anda dapat menggunakan perintah 'install' untuk menyalin file ke direktori yang ada atau membuat membuat direktori tujuan baru jika belum ada.
Opsi 1
install -D filename some/deep/directory/filename
menyalin file ke direktori baru atau yang sudah ada dan memberikan izin nama file standar 755
Opsi 2
install -D filename -m640 some/deep/directory/filename
sesuai Opsi 1 tetapi memberikan nama file 640 izin.
Opsi 3
install -D filename -m640 -t some/deep/directory/
sesuai Opsi 2 tetapi menargetkan nama file ke direktori target sehingga nama file tidak perlu ditulis dalam sumber dan target.
Opsi 4
install -D filena* -m640 -t some/deep/directory/
sesuai Opsi 3 tetapi menggunakan wildcard untuk banyak file.
Ini berfungsi dengan baik di Ubuntu dan menggabungkan dua langkah (pembuatan direktori kemudian menyalin file) menjadi satu langkah tunggal.
Ini sangat terlambat tetapi mungkin membantu pemula di suatu tempat. Jika Anda perlu 'otomatis' membuat folder rsync harus menjadi teman terbaik Anda. rsync / path / ke / sourcefile / path / ke / tragetdir / thatdoestexist /
cp
(seperti yang dijawab oleh Paul Whipp), tetapi ini tidak umum seperti yang diminta OP. Hal ini dapat menyalina/foo/bar/file
keb/foo/bar/file
tetapi tidak dapat menyalinfile
keb/foo/bar/file
. (Yaitu hanya berfungsi untuk membuat direktori induk yang sudah ada dalam kasus file pertama, tetapi tidak dapat membuat direktori sewenang-wenang)Jawaban:
(tidak ada opsi untuk
cp
).sumber
test -d
:mkdir -p
masih berhasil walaupun direktori sudah ada.mkdir
adalah builtin di BusyBox;)$d
adalah variabel yang mungkin berisi direktori yang dimaksud. Maksud saya, jika Anda harus mengulanginya tiga kali, Anda cenderung menugaskannya ke variabel terlebih dahulu.Jika kedua hal berikut ini benar:
cp
(dan bukan, misalnya, versi Mac), danmaka Anda dapat melakukan ini dengan
--parents
benderacp
. Dari halaman info (dapat dilihat di http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation atau denganinfo cp
atauman cp
):Contoh:
sumber
macports
Anda dapat menginstal coreutils dangcp
.Jawaban singkat
Untuk menyalin
myfile.txt
ke/foo/bar/myfile.txt
, gunakan:Bagaimana cara kerjanya?
Ada beberapa komponen untuk ini, jadi saya akan membahas semua langkah demi langkah sintaksis.
The mkdir utilitas, sebagaimana ditentukan dalam standar POSIX , membuat direktori. The
-p
argumen, per dokumen, akan menyebabkan mkdir untukartinya ketika memanggil
mkdir -p /foo/bar
, mkdir akan membuat/foo
dan/foo/bar
jika/foo
belum ada. (Tanpa-p
, itu malah akan menimbulkan kesalahan.The
&&
Operator daftar, seperti yang didokumentasikan dalam standar POSIX (atau pengguna Bash jika Anda suka), memiliki efek yangcp myfile.txt $_
hanya dijalankan jikamkdir -p /foo/bar
mengeksekusi berhasil. Ini berarticp
perintah tidak akan mencoba untuk mengeksekusi jikamkdir
gagal karena salah satu dari banyak alasan itu mungkin gagal .Akhirnya,
$_
kitacp
menganggap argumen kedua adalah "parameter khusus" yang berguna untuk menghindari pengulangan argumen panjang (seperti path file) tanpa harus menyimpannya dalam variabel. Per manual Bash , itu:Dalam hal ini, itulah yang
/foo/bar
kami berikanmkdir
. Jadicp
perintah diperluas kecp myfile.txt /foo/bar
, yang menyalinmyfile.txt
ke/foo/bar
direktori yang baru dibuat .Perhatikan bahwa
$_
ini bukan bagian dari standar POSIX , sehingga secara teoritis varian Unix mungkin memiliki shell yang tidak mendukung konstruk ini. Namun, saya tidak tahu adanya kerang modern yang tidak mendukung$_
; tentu Bash, Dash, dan zsh semua lakukan.Catatan terakhir: perintah yang saya berikan di awal jawaban ini mengasumsikan bahwa nama direktori Anda tidak memiliki spasi. Jika Anda berurusan dengan nama dengan spasi, Anda harus mengutipnya sehingga kata-kata yang berbeda tidak diperlakukan sebagai argumen berbeda dengan
mkdir
ataucp
. Jadi perintah Anda sebenarnya akan terlihat seperti:sumber
Pertanyaan yang lama, tapi mungkin saya bisa mengusulkan solusi alternatif.
Anda dapat menggunakan
install
program ini untuk menyalin file Anda dan membuat jalur tujuan "on the fly".Namun ada beberapa aspek yang perlu dipertimbangkan:
Anda dapat dengan mudah mengubah # 2 dengan menambahkan
-m
opsi untuk mengatur izin pada file tujuan (contoh:-m 664
akan membuat file tujuan dengan izinrw-rw-r--
, seperti halnya membuat file baru dengantouch
).Dan di sini adalah tautan tak tahu malu ke jawaban yang saya terinspirasi oleh =)
sumber
755
(rwxr-xr-x
) izin, yang mungkin tidak diinginkan. Anda dapat menentukan sesuatu yang lain dengan-m
saklar, tetapi saya tidak dapat menemukan cara untuk hanya menyimpan izin file :(Fungsi Shell yang melakukan apa yang Anda inginkan, menyebutnya salinan "mengubur" karena menggali lubang untuk tempat tinggal file:
sumber
dirname $2
juga$2
sebagai argumendirname
. Sepertimkdir -p "$(dirname "$2")"
. Tanpa ini mengutip$2
dicp
tidak berguna;)dirname "$2"
&& cp -r "$ 1" "$ 2"; Perhatikan bahwa backtick di sekitardirname $2
tidak muncul karena SO mem-parsing mereka sebagai penanda kode.Inilah satu cara untuk melakukannya:
dirname
akan memberi Anda induk dari direktori tujuan atau file. mkdir -p `dirname ...` kemudian akan membuat direktori itu memastikan bahwa ketika Anda memanggil cp -r direktori basis yang benar sudah ada.Keuntungan over - orang tua ini adalah bahwa ia bekerja untuk kasus di mana elemen terakhir di jalur tujuan adalah nama file.
Dan itu akan bekerja pada OS X.
sumber
install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there
sumber
there
adalah file terakhir dan bukan subdirektori akhir.dengan segala hormat saya untuk jawaban di atas, saya lebih suka menggunakan rsync sebagai berikut:
contoh:
sumber
rsync
lebih dapat diprediksi daripadacp
. Misalnya, jika saya ingincp /from/somedir /to-dir
maka cp berperilaku berbeda jika/to-dir
sudah ada: Jika/to-dir
ada, makacp
akan membuat/to-dir/some-dir
, jika tidak, hanya konten/from/somedir
ditempatkan ke/to-dir
. Namun,rsync
berperilaku sama dalam hal, yaitu,/to-dir/some-dir
akan selalu dibuat.Hanya untuk melanjutkan dan memberikan solusi kerja yang lengkap, dalam satu baris. Hati-hati jika Anda ingin mengganti nama file Anda, Anda harus memasukkan cara untuk memberikan path dir bersih ke mkdir. $ fdst dapat berupa file atau dir. Kode selanjutnya harus berfungsi dalam hal apa pun.
atau spesifik bash
sumber
Cukup tambahkan berikut ini di .bashrc Anda, tweak jika Anda perlu. Bekerja di Ubuntu.
Misalnya Jika Anda ingin menyalin file 'test' ke direktori tujuan 'd' Gunakan,
mkcp pertama-tama akan memeriksa apakah direktori tujuan ada atau tidak, jika tidak maka buatlah dan salin file sumber / direktori.
sumber
mkdir -p
. Itu akan berhasil bahkan jika sudah ada.Ini untukku
sumber
man cp
:-R If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
Saya menulis skrip dukungan untuk cp, yang disebut CP (huruf besar) yang dimaksudkan untuk melakukan hal ini. Script akan memeriksa kesalahan di jalur yang Anda masukkan (kecuali yang terakhir yang menjadi tujuan) dan jika semuanya baik-baik saja, ia akan melakukan langkah mkdir -p untuk membuat jalur tujuan sebelum memulai penyalinan. Pada titik ini utilitas cp reguler mengambil alih dan setiap sakelar yang Anda gunakan dengan CP (seperti -r, -p, -rpL akan disalurkan langsung ke cp). Sebelum Anda menggunakan skrip saya, ada beberapa hal yang perlu Anda pahami.
CP tidak memiliki kemewahan untuk mengambil isyarat dari jalur yang ada, sehingga harus memiliki beberapa pola perilaku yang sangat tegas. CP mengasumsikan bahwa item yang Anda salin dijatuhkan di jalur tujuan dan bukan tujuan itu sendiri (alias, salinan yang diubah namanya dari file sumber / folder). Berarti:
Perilaku CP default ini dapat diubah dengan sakelar "--rename". Dalam hal ini, diasumsikan demikian
Beberapa catatan penutup: Seperti dengan cp, CP dapat menyalin beberapa item sekaligus dengan jalur terakhir yang didaftarkan dianggap sebagai tujuan. Itu juga bisa menangani jalur dengan spasi selama Anda menggunakan tanda kutip.
CP akan memeriksa jalur yang Anda letakkan dan memastikan keberadaannya sebelum melakukan penyalinan. Dalam mode ketat (tersedia melalui saklar --strict), semua file / folder yang disalin harus ada atau tidak ada salinan yang terjadi. Dalam mode santai (--relaxed), penyalinan akan dilanjutkan jika setidaknya ada satu item yang Anda daftarkan. Mode santai adalah default, Anda dapat mengubah mode sementara melalui sakelar atau secara permanen dengan mengatur variabel easy_going di awal skrip.
Berikut cara menginstalnya:
Di terminal non-root, lakukan:
Di gedit, rekatkan utilitas CP dan simpan:
sumber
cp
memiliki beberapa penggunaan:@ AndyRoss menjawab bekerja untuk
gaya
cp
, tetapi melakukan hal yang salah jika Anda menggunakangaya
cp
.Saya pikir "DEST" tidak jelas tanpa garis miring dalam penggunaan ini (yaitu di mana direktori target belum ada), yang mungkin mengapa
cp
tidak pernah menambahkan opsi untuk ini.Jadi, inilah versi saya dari fungsi ini yang memberlakukan garis miring pada direktori tujuan:
sumber
Baru saja mengalami masalah yang sama. Pendekatan saya adalah hanya memasukkan file ke arsip seperti:
tar cf your_archive.tar file1 /path/to/file2 path/to/even/deeper/file3
tar secara otomatis menyimpan file dalam struktur yang sesuai dalam arsip. Jika Anda berlari
tar xf your_archive.tar
file diekstraksi ke dalam struktur direktori yang diinginkan.
sumber
Seperti yang disarankan di atas oleh help_asap dan spongeman, Anda dapat menggunakan perintah 'install' untuk menyalin file ke direktori yang ada atau membuat membuat direktori tujuan baru jika belum ada.
Opsi 1
install -D filename some/deep/directory/filename
menyalin file ke direktori baru atau yang sudah ada dan memberikan izin nama file standar 755
Opsi 2
install -D filename -m640 some/deep/directory/filename
sesuai Opsi 1 tetapi memberikan nama file 640 izin.
Opsi 3
install -D filename -m640 -t some/deep/directory/
sesuai Opsi 2 tetapi menargetkan nama file ke direktori target sehingga nama file tidak perlu ditulis dalam sumber dan target.
Opsi 4
install -D filena* -m640 -t some/deep/directory/
sesuai Opsi 3 tetapi menggunakan wildcard untuk banyak file.
Ini berfungsi dengan baik di Ubuntu dan menggabungkan dua langkah (pembuatan direktori kemudian menyalin file) menjadi satu langkah tunggal.
sumber
Ini sangat terlambat tetapi mungkin membantu pemula di suatu tempat. Jika Anda perlu 'otomatis' membuat folder rsync harus menjadi teman terbaik Anda. rsync / path / ke / sourcefile / path / ke / tragetdir / thatdoestexist /
sumber
Ini mungkin berhasil, jika Anda memiliki jenis yang tepat
rsync
.sumber
Salin dari sumber ke jalur yang tidak ada
CATATAN: perintah ini menyalin semua file
cp –r
untuk menyalin semua folder dan kontennya$_
berfungsi sebagai tujuan yang dibuat dalam perintah terakhirsumber
Sederhana
harus melakukan trik.
sumber
Katakanlah Anda sedang melakukan sesuatu seperti
di mana A / B / C / D adalah direktori yang belum ada
Solusi yang mungkin adalah sebagai berikut
berharap itu bisa membantu!
sumber