sh recursive copy (cp -r) - Cara mengecualikan subfolder

8

Saya perlu menjalankan skrip jarak jauh menggunakan sshvia Ruby( net / ssh ) untuk menyalin folder secara rekursif dan mengecualikan subfolder. Saya mencari cara tercepat untuk melakukannya sehingga rsynctidak baik. Juga, saya mengerti bahwa sshmenggunakan shdan tidak bash.

Dalam bash saya lakukan:

cp -r srcdir/!(subdir) dstdir

dan itu bekerja dengan baik. Namun ketika saya meluncurkan skrip melalui sshsaya menerima kesalahan

sh: 1: Syntax error: "(" unexpected

karena menggunakan sh.

Saya telah memeriksa shhalaman manual, tetapi tidak ada opsi untuk mengecualikan file.

Apakah asumsi saya sshmenggunakan yang shbenar? Ada saran alternatif?

EDIT 1: Dalam hal ini berguna, output dari sudo cat /etc/shellsadalah sebagai berikut:

# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/tmux
/usr/bin/screen

EDIT 2: Oke. Jadi bash itu tersedia dan sepertinya tidak menjadi masalah. Saya telah memverifikasi bahwa ssh sebenarnya menggunakan bash. Masalah ini tampaknya terkait dengan keluarnya tanda kurung atau tanda seru. Saya telah mencoba menjalankan perintah dari shell (macos) dan ini adalah perintah yang sebenarnya:

ssh -i .ssh/key.pem ubuntu@X.X.X.X 'mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'

Dengan cara ini saya menerima kesalahan yang berbeda

cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory

EDIT 3: Berdasarkan komentar saya telah mengubah perintah saya menambahkanextglob

Jika saya gunakan

ssh -i .ssh/key.pem ubuntu@X.X.X.X 'shopt -s extglob; mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant'

Saya menerima kesalahan berikut:

cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory

Jika saya tidak lepas kurung saya dapatkan

bash: -c: line 0: syntax error near unexpected token `('
Rojj
sumber
3
ssh(well sshd) menggunakan shell login dari pengguna jarak jauh. Bisa apa saja.
Stéphane Chazelas
Unix tidak memiliki folder, hanya direktori. :)
tchrist
1
Dalam situasi seperti ini saya sering ingin hanya mengembangkan skrip pada host jarak jauh, maka baik 1) meninggalkannya di sana, ssh in (terprogram jika perlu) dan jalankan atau 2) jika itu berubah setiap kali, scp lebih, jalankan via ssh, lalu hapus. Langkah tambahan mungkin, tetapi Anda tidak berakhir dengan melarikan diri dari mimpi buruk dan gumpalan meluas secara lokal, bukan jarak jauh dan semua itu. Kalau tidak, saya akan selalu menggunakan format heredoc seperti @ StéphaneChazelas menggunakan di bawah ini.
Josh Rumbut

Jawaban:

10

SSH menjalankan shell login Anda pada sistem jarak jauh, apa pun itu. Tetapi !(foo)membutuhkan shopt -s extglob, yang Anda mungkin tidak mengatur pada remote.

Coba ini untuk melihat apakah SSH menjalankan Bash di sisi jarak jauh:

ssh me@somehost 'echo "$BASH_VERSION"'

Jika itu mencetak apa pun, tetapi skrip startup Anda tidak disetel extglob, Anda dapat melakukannya dengan tangan pada perintah yang diteruskan ke ssh:

ssh me@somehost 'shopt -s extglob
    echo srcdir/!(subdir)'                                 
 # or
ssh me@somehost $'shopt -s extglob\n echo srcdir/!(subdir)'   

extglob mempengaruhi penguraian baris perintah, dan hanya berlaku setelah baris baru, jadi kita harus meletakkan baris baru literal di sana, tanda titik koma tidak cukup.

ssh me @ somehost 'shopt -s extglob; echo srcdir /! (subdir) '

Juga bukan bahwa jika Anda lolos dari kurung dengan garis miring terbalik, mereka kehilangan sifat khusus mereka, seperti karakter gumpal lainnya. Ini bukan yang ingin Anda lakukan dalam kasus ini.

$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)
ilkkachu
sumber
10

Saya tidak tahu mengapa Anda berpikir bahwa rsync akan lambat. Kecepatan salinan sebagian besar ditentukan oleh kecepatan disk. Rsync memiliki banyak opsi untuk menentukan apa yang ingin Anda sertakan dan singkirkan, sehingga memberi Anda kontrol yang jauh lebih baik daripada shell globbing.

Seperti yang dinyatakan dalam manual bash, !(patter)ini hanya dikenali dalam bash jika extglobdisetel. Dalam contoh Anda, Anda tidak menetapkan extglob. Lebih lanjut, bashdimulai seperti shmasih bash, tetapi akan menonaktifkan beberapa ekstensi untuk kompatibilitas.

Server SSH akan memulai shell login pengguna, seperti yang ditentukan dalam /etc/passwd. Anda dapat mengganti shell, atau menggunakan shell itu untuk memulai shell lain yang lebih sesuai dengan kebutuhan Anda.

RalfFriedl
sumber
Saya diuji dengan time. time cp -r mesh/!(constant) N-> 1.04s nyata dan time rsync -a mesh/ N --exclude=constant-> 1.8s nyata
Rojj
7
@ Rojj itu perbandingan apel dengan jeruk. Untuk satu hal, Anda menggunakan -a untuk rsync tetapi tidak untuk cp. Itu melibatkan pelestarian izin dan atribut lainnya, sehingga Anda tidak benar-benar melakukan hal yang sama.
Wildcard
6

Beberapa catatan pertama:

  • server ssh tidak mulai shmenafsirkan baris perintah yang dikirim oleh klien, ia menjalankan shell login pengguna pada host jarak jauh, seperti that-shell -c <the-string-provided-by-the-client>. Shell login pengguna jarak jauh bisa berupa apa saja. Ingatlah bahwa beberapa kerang suka tcsh, fishatau rcmemiliki sintaks yang sangat berbeda dari itu sh.
  • itu benar-benar baris perintah, atau lebih tepatnya string (yang dapat berisi karakter baris baru, jadi beberapa baris). Bahkan jika Anda lakukan ssh host cmd arg1 'arg 2'di mana cmd, arg1dan arg 2tiga argumen dilewatkan ke ssh, sshmerangkai argumen-argumen dengan ruang dan benar-benar mengirimkan cmd arg1 arg 2string untuk sshd, dan remote shell akan dibagi ke dalam cmd, arg1, argdan 2.
  • !(subdir)adalah operator glob ( kshoperator glob juga didukung oleh zsh -o kshglobdan bash -O extglob). Seperti semua gumpalan, itu mengecualikan file tersembunyi, jadi waspadalah mungkin ada file lain yang dikecualikan.

Di sini, untuk menghindari masalah dengan mencari sintaks yang tepat untuk shell jarak jauh, Anda dapat benar-benar memberi tahu shell lain untuk memulai shell yang Anda inginkan dan mengumpankannya kode melalui stdin (salah satu opsi yang tercantum di Cara menjalankan sederhana sewenang-wenang perintah lebih dari ssh tanpa mengetahui shell login dari pengguna jarak jauh? )

ssh host 'bash -O extglob -O dotglob' << 'EOF'
cp -r srcdir/!(subdir) dstdir/
EOF

bash -O extglob -O dotglobadalah baris perintah yang dipahami sama oleh semua shell utama, termasuk yang mirip Bourne, csh, rc, fish ... Di atas akan berfungsi selama bashdiinstal dan berada di pengguna $PATH(default $PATH, mungkin dimodifikasi oleh pengguna) shell login seperti dengan ~/.zshenvuntuk zsh, ~/.cshrcuntuk csh, ~/.bashrcuntuk bash).

POSIXly (meskipun dalam praktiknya, Anda mungkin menemukan bahwa lebih banyak sistem memiliki bashperintah daripada paxperintah), Anda dapat melakukannya:

ssh host sh << 'EOF'
cd srcdir && pax -rw -'s|^\.//\./subdir\(/.*\)\{0,1\}$||' .//. /path/to/destdir/
EOF

-smenerapkan pergantian ke jalur yang ditransfer. Ketika penggantian itu tidak menghasilkan apa-apa, file tersebut dikecualikan. Masalahnya adalah bahwa substitusi juga berlaku untuk target symlink. Itu sebabnya kami menggunakan di .//.atas untuk mengurangi kemungkinan symlink terpengaruh.

Stéphane Chazelas
sumber
4

Saya tidak berpikir sshterbatas untuk menggunakan sh. Ini lebih tergantung pada apa yang diinstal pada sistem target, bagaimana pengguna diatur, dan apa shell yang diizinkan masuk /etc/shells.

Apakah Anda mempertimbangkan chshperintahnya?

RudiC
sumber
4

Jika Anda ingin melakukannya dengan cepat, Anda dapat melihatnya rsyncdengan algoritma enkripsi yang berbeda. Ini memberi Anda pilihan untuk dengan mudah mengecualikan dll, dengan kecepatan pengorbanan tidak banyak.

rsync -aHAXxv --numeric-ids --progress -e "ssh -T -c arcfour -o Compression=no -x" user@<source>:<source_dir> <dest_dir>

bersama-sama dengan menambahkan arcfourenkripsi ke garis start dengan Ciphersdi /etc/ssh/ssh_config, jika belum diaktifkan, memberikan kecepatan yang dapat diterima.

PERINGATAN: arcfourEnkripsi tidak aman . JANGAN menjalankan ini di saluran yang tidak aman. Jika Anda khawatir tentang akses ke server dari saluran tidak aman menggunakan arcfourenkripsi, ubah etc/ssh/ssh_configdengan bagian khusus host untuk host sumber Anda - Buat Hostbagian di ssh_config Anda untuk host sumber Anda, Anda dapat menggunakannya Ciphers arcfouruntuk mencerminkan -csaklar di atas , yang membatasi arcfourenkripsi hanya untuk host ini.

Untuk detailnya, lihat ssh_confighalaman manual.

Namun, jika CPU Anda mendukung set instruksi AES-NI, coba beralih ke [email protected] (ya, itulah nama sandi, termasuk @ barang), yang akan menggunakan blazingly fast (dengan AES-NI) AES128 -GCM.

Jadi, dengan CPU yang mendukung AES-NI, ubah "ssh -T -c arcfour -o Compression=no -x"ke "ssh -T -c [email protected] -o Compression=no -x"untuk hasil yang lebih aman.

Penjelasan

rsync

  • (Jangan gunakan -z, itu jauh lebih lambat)
  • a: mode arsip - rescursive, mempertahankan pemilik, mempertahankan izin, mempertahankan waktu modifikasi, mempertahankan grup, menyalin symlink sebagai symlink, mempertahankan file perangkat.
  • H: mempertahankan tautan keras
  • A: mempertahankan ACL
  • X: mempertahankan atribut yang diperluas
  • x: jangan melewati batas sistem file
  • v: meningkatkan verbositas
  • --numeric-ds: jangan memetakan nilai uid / gid berdasarkan nama pengguna / grup
  • jika Anda perlu menyinkronkan, tambahkan --delete: hapus file asing dari direktori tujuan (pembersihan diferensial selama sinkronisasi)
  • --progress: tampilkan kemajuan selama transfer

ssh

  • T: matikan pseudo-tty untuk mengurangi beban cpu di tujuan.
  • c arcfour: gunakan enkripsi SSH terlemah tetapi tercepat. Harus menentukan "Ciphers arcfour" di sshd_config pada tujuan.
  • o Compression=no: Matikan kompresi SSH.
  • x: matikan penerusan X jika diaktifkan secara default.

Daging sapi ada dalam sshopsi - jika Anda hanya menggunakan rsync -avdan -e ssh -T -c arcfour -o Compression=no -x"bagian, Anda bisa mendapatkan kecepatan ini juga.


Perbandingan:

  • 13,6 MB / s rsync -az
  • 16,7 MB / s scp -Cr
  • 44,8 MB / s rsync -a
  • 59,8 MB / s sftp
  • 61.2 MB / s scp -r
  • 61,4 MB / s sftp -R 128 -B 65536
  • 62,4 MB / s rsync -a -P -e "ssh -T -c arcfour -o Compression=no -x"
  • 143,5 MB / s scp -r -c arcfour
  • 144,2 MB / s sftp -oCiphers=arcfour

Sumber :

https://gist.github.com/KartikTalwar/4393116

http://nz2nz.blogspot.com/2018/05/rsync-scp-sftp-speed-test.html

emk2203
sumber
3
Yah, mereka tampaknya berjalan cp -rdalam sistem jarak jauh, sehingga enkripsi yang digunakan oleh koneksi SSH tidak benar-benar relevan. Dalam hal apapun arcfourdianggap agak rusak dan OpenSSH menonaktifkannya bersama dengan orang lain di server secara default sejak versi 6.7 (2014-10-06) . Bagaimanapun, ssh -o Ciphers='aes128-ctr'berikan saya sekitar 90 MB / s, yang seharusnya cukup cepat pada tautan 1 Gbit / s.
ilkkachu
Ya, arcfour rusak, tetapi seharusnya bukan shell AMAN untuk kasus ini, tetapi lebih 'shell nyaman' tanpa penekanan pada enkripsi. Saya tidak akan menggunakan ini melalui koneksi yang tidak aman, itu benar. Jika 'aes128-ctr' cukup cepat, ia bisa dan harus digunakan sebagai gantinya.
emk2203
Lihat juga jawaban saya yang diperluas untuk penggunaan dengan CPU yang mendukung AES-NI.
emk2203
2

Sesuai perhitungan saya, salinan lengkap tercepat selalu menggunakan 'tar' (di sini mengasumsikan GNU taratau kompatibel).

mkdir -p photos2 &&
  tar -C photos -cf - --exclude=./.thumbcache . |
  tar -C photos2 -xpf -

Dan tarmemiliki banyak pilihan untuk memanipulasi atribut, izin dan pemilihan / pengecualian file. Sebagai contoh, perintah di atas tidak termasuk subfolder tingkat atas yang disebut .thumbcache saat menyalin.

Lam Das
sumber
Perhatikan bahwa --exclude=.thumbcachetidak termasuk semua yang .thumbcachefile, tidak hanya satu di tingkat atas. Dengan GNU tar(tidak bsdtar), Anda hanya dapat menggunakan --exclude=./.thumbcacheuntuk mengecualikan .thumbcachefile tingkat atas .
Stéphane Chazelas