Latar Belakang
Di Linux Anda dapat:
- Daftar grup file dengan
ls Filename*
- Hapus sekelompok file dengan
rm Filename*
- Pindahkan sekelompok file dengan
mv Filename* /New/Directory
- Tetapi Anda tidak dapat menyalin sekelompok file dengan:
cp Filename* *.bak
Ubah cp
perintah Linux untuk menyalin grup file
Saya memiliki sekelompok file yang ingin saya salin tanpa memasukkan nama satu per satu dan menggunakan cp
perintah:
$ ls gmail-meta3*
gmail-meta3 gmail-meta3-REC-1558392194-26467821
gmail-meta3-LAB-1558392194-26467821 gmail-meta3-YAD-1558392194-26467821
Bagaimana saya bisa menggunakan sesuatu seperti perintah DOS lama copy gmail-meta3* *.bak
?
Saya tidak ingin mengetik perintah serupa empat kali:
cp gmail-meta3-LAB-1558392194-26467821 gmail-meta3-LAB-1558392194-26467821.bak
Saya mencari skrip / fungsi / aplikasi yang menerima parameter untuk grup nama file lama dan baru dan bukan sesuatu dengan nama file hard-coded. Misalnya, pengguna dapat mengetik:
copy gmail-meta3* *.bak
atau mereka dapat mengetik:
copy gmail-meta3* save-*
command-line
cp
ms-dos
WinEunuuchs2Unix
sumber
sumber
touch aa ab ba; mkdir bb; cp a* b*; ls *
*
untuk nama file sumber tetapi tidak untuk nama file target. Seperti wildcard pengganti (saya pikir##
disarankan tapi saya condong ke arah%
) harus digunakan untuk target. Saya pikir ini yang Anda perkuat? Saya tidak berharap untuk mengubahcp
perintah sama sekali. Cukup buat skrip wrapper yang disebutcopy
yang meniru (sesuai alasan) perintah salin DOS.Jawaban:
Berikut adalah contoh dari satu penggunaan atipikal
sed
, yang berlaku untuk tugas ini:Dengan cara ini, sebenarnya,
sed
tidak akan mengubah file, karena kami tidak memberikan perintah apa pun''
, tetapi karena opsi-i[suffix]
itu akan membuat salinan cadangan dari setiap file. Saya menemukan pendekatan ini ketika saya mencari. Apakah ada cara untuk membuat salinan cadangan file, tanpa mengetikkan namanya dua kali?sumber
$ time sed -i.bak '' gmail-meta3*
=real 0m0.069s
real 0m0.037s
. Jika file dihapus dan menjalankan waktu dekat kedua untukcp
kecepatan:real 0m0.051s
.sed
lebih cepat ketika file target sudah ada tetapicp
lebih lambat ketika file target ada. Saya benar-benar membersihkan cache dan buffer daripadasync
ketika melakukan tes waktu yang besar tapi saya tidak melakukannya saat ini. Karena hal ini dapat menyimpang ke dalam opera sabun luar-topik yang sama sekali berbeda, saya menyesal membagikan hasil tes saya :( Apakah sudah terlambat untuk berpura-pura percakapan ini tidak pernah terjadi? FYI pesan gmail metadata ukuran 2,5 MB dan 3 file indeks sekitar 800 KB Juga bukan hard disk, ini adalah Samsung Pro 960 NVMe SSD pada 4 saluranfree
perintah. Tulisan aktual ke perangkat dilakukan pada saat yang dipilih oleh algoritma yang memperhitungkan usia cache dan tekanan memori pada mesin. Jika Anda mencoba beberapa tes, maka file pertama yang dibaca akan keluar dari disk, tetapi yang berikutnya kemungkinan besar akan langsung keluar dari memori (lihatsync; echo 3 > /proc/sys/vm/drop_caches
).cp
perintah, tapi saya tidak bisa mengatakan ada perbedaan kinerja yang signifikan .Anda bisa menggunakan
find
:Itu akan menemukan dalam direktori saat ini
.
semua file dengan nama yang cocok dengan pola glob (ingat tanda kutip tunggal di sekitar pola untuk mencegah globbing shell). Untuk setiap file yang ditemukan, itu akan munculcp
dari nama ke nama.bak. The \; pada akhirnya memastikan itu akan melakukan masing-masing file secara individual alih-alih melewati semuanya sekaligus. Kedalaman maksimal sebagai 1 hanya mencari direktori cuurent alih-alih berulang.sumber
find . -max-depth 1 -name '"$1"'' -exec cp "{}" "{}$2" \;
ketika $ 1 adalah sumber dan $ 2 adalah ekstensi?Anda dapat menggunakan satu
for
lingkaran denganbash
. Biasanya, saya cukup mengetiknya sebagai satu-liner karena ini bukan tugas yang sering saya lakukan:Namun, jika Anda memerlukannya sebagai skrip:
Penggunaannya mirip dengan
rename
. Untuk mengetes:sumber
$ time for f in gmail-meta3* ; do cp -a "$f" "${f}.bak" ; done
=real 0m0.046s
0.046
detik yang berarti 0 detik untuk persepsi manusia. Saya hanya mencoba menunjukkan bagaimana saya menguji jawaban yang diposting dan menyampaikan informasi menarik kepada pemirsa yang melihatsed
perintah di atas. Atau setidaknya saya tertarik membandingkansed
dengancp
....cp
lebih cepat daripada solusi dengansed
sekalipun. Jadi itu alasan untuk perayaan :)-a
adalah operator uji non-standar. Kenapa tidak digunakan-e
? (2) "Tidak dapat membuat direktori sementara." adalah pesan kesalahan yang agak menyesatkan. (3) Kenapa tidak pakai sajamktemp -d
? (4) Anda harus menguji status keluar. Misalnya, Anda harus mengatakan! mkdir "$FOLDER" && echo "Unable to create temporary directory." && return 1
ataumkdir "$FOLDER" || { echo "Unable to create temporary directory."; return 1;}
. Demikian juga untukcp
danrename
(dan bahkan mungkinpushd
, jika Anda ingin berhati-hati). … (Lanjutan)$@
; katakan"$@"
. (5b) Tidak perlu menggunakan{
dan}
ketika Anda referensi variabel cara Anda lakukan ("${FOLDER}"
,"${PATTERN}"
dan"${file}"
); lakukan saja"$FOLDER"
,"$PATTERN"
dan"$file"
. (6) Ini mengasumsikan bahwa file berada di direktori saat ini.cps 's/$/.bak/' d/foo
akan menyalind/foo
kefoo.bak
dalam direktori saat ini, bukand/foo.bak
.Yang paling mungkin Anda dapatkan dari paradigma DOS adalah
mcp
(darimmv
paket):Jika
zsh
tersedia,zmv
modul kontribusinya mungkin sedikit lebih dekat:Saya akan menghindari
ls
- varian pada jawaban Anda sendiri yang aman untuk spasi putih (termasuk baris baru)atau mungkin
sumber
mmv
adalah paket tetapi dalam komentar Anda mengatakan perintah itumcp
tetapi kemudian dalam perintah yang Anda gunakanmmv
yang juga merupakan perintah dalammmv
paket. Saya suka arahprintf
contoh dan dalam skrip dipoles saya akan memastikan $ 1 dan $ 2 disahkan. +1 untuk mendapatkan bola bergulir :)mcp
ini hanya sinonim untukmmv -c
printf
perintah saya tidak pernah menggunakan benar. Apakah Anda mengatakanprintf '%s\0' "$1"*
akan bekerja jikagmail-meta3
dilewatkan sebagai parameter 1?cps gmail-meta3*
dan kemudian menulisprintf '%s\0
"$ @" | sementara ... `dalam fungsi. Atau cukup gunakanfor f; do cp -- "$f" "$f.bak"; done
(seperti jawaban xiota , tetapi sebagai fungsi)zmv
Anda dapat menggunakan mode "pengganti pengganti", yang menurut saya sedikit lebih mudah untuk dilakukan:zmv -W -C 'gmail-meta3*' '*.bak'
solusi rsync saja
Jika Anda hanya ingin membuat cadangan file Anda, Anda dapat menyalinnya ke direktori baru
rsync /path/to/dir/Filename* /path/to/backupdirectory
Ini akan menyalin
Filename
file dari/path/to/dir/
ke/path/to/backupdirectory
.rsync + filerename
Jika Anda ingin file cadangan Anda memiliki suffix, semuanya menjadi rusak dengan
rsync
...rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak
Ini akan menimpa file yang ada ... dengan file yang ada (
-I
) tetapi hanya jika mereka (-u
) lebih baru (yang tidak) dan membuat cadangan, dengan akhiran.Anda juga dapat melakukannya di direktori yang sama. Tetapi lebih baik kecualikan cadangan yang ada.
rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak --exclude '*.bak'
sumber
rsycnc
jadi saya memutakhirkannya tetapi, metode yang lebih sederhana adalahcp Filename* /path/to/backup/dir
karena file tidak perlu*.bak
pemesat jika berada di direktori yang terpisah.Yang ini harus dilakukan seperti yang diminta:
Pemakaian:
Saya memilih
?
karena#
harus dikutip ketika itu adalah karakter pertama dari pola, kalau tidak itu akan diakui sebagai awal dari komentar.Uji:
Beberapa versi skrip sebelumnya untuk menambahkan akhiran:
Mirip dengan jawaban @ WinEunuuchs2Unix, tapi saya pikir lebih fleksibel dan tidak parsing
ls
:Letakkan ini di
.bashrc
.Pemakaian:
Alternatif, dengan akhiran sebagai argumen terakhir ( via dan via ):
Pemakaian:
sumber
copy gmail-meta3* old-meta3*
. Dalam jawaban saya, saya tidak tahu bagaimana cara masuk*
ke nama tujuan seperti pertanyaan saya yang diminta ...*
ditafsirkan oleh shell, jadi fungsinya tidak akan tahu tentang itu. Anda memerlukan beberapa karakter lain atau mengutipnya, lalu ganti dengan nama file asli dalam fungsi tersebut.#
bisa digunakan sebagai pengganti wildcard*
? Jadi Anda bisa mengetikcopy filenames# save-#
. Saya pikir Anda ingin karakter wildcard sama untuk sumber dan target.Saya menulis ini satu baris ke dalam saya
~/.bashrc
. Jawaban yang jauh lebih baik menggunakanfind
dapat saya kira. Bahkan jawaban yang lebih baik dapat ditulis dalam C. Mudah-mudahan T&J ini menggulirkan jawaban yang lebih baik:for f in "$1"*; do
:$1
adalahgmail-meta3
parameter danf
daftar file yang cocok. Gabungan cara ini untuk gmail-meta3, gmail-meta3-LAB-9999, dll. Lakukan hal berikut[[ ! "$f" == *"$2" ]] &&
:$f
sama seperti dif
atas.$2
adalah.bak
parameter yang dilewati. Gabungan ini berarti jika nama file tidak berakhir.bak
(karena kami tidak ingin menyalin.bak
dan membuat.bak.bak
) maka lakukan hal berikutcp -a "$f" "$f$2";
salin gmail-meta3 ke gmail-meta3.bak, dll.done
: loop kembali dan ambil nama file berikutnya digmail-meta3
daftar *.cps gmail-meta3 .bak
Output SampelMenggunakan pertanyaan sebagai contoh di sini adalah bagaimana tampilannya dalam tindakan:
Catatan: Ini menggunakan
-a
bendera dengancp
perintah untuk menyimpan stempel waktu dan memberi Anda pemahaman yang lebih baik tentang cadangan file Anda.Perhatikan bagaimana salinan file memiliki tanggal dan waktu yang sama persis seperti aslinya. Jika
-a
parameter dihilangkan mereka akan diberi tanggal dan waktu saat ini dan tidak akan terlihat seperti cadangan yang sebenarnya kecuali bahwa ukuran file akan sama.sumber
ls
find
saya menganggap Anda sadar akan bahaya parsingls
? Tetapi dalam kasus Anda tidak diperlukan: lakukan sajafor file in "$1"*; do copy -a "$file" "$file$2"; done
- ini benar-benar aman dan jauh lebih sederhana daripada segala jenis tipuan melaluils
ataufind
dan satuwhile
loop.Metode lain untuk mencapai kebutuhan Anda adalah menyalin file ke direktori sementara dan menggunakan
rename
perintah untuk mengganti nama mereka.Jika Anda membutuhkannya sebagai skrip, Anda dapat menggunakannya seperti itu
Dan Anda bisa menggunakannya seperti ini:
Ini sebuah contoh
sumber