sh recursive copy (cp -r) - Как исключить подпапку

8

Мне нужно запустить удаленный скрипт , используя с sshпомощью Ruby( нетто / SSH ) рекурсивно скопировать папку и исключить папку. Я ищу самый быстрый способ сделать это, так что rsyncэто не хорошо. Также я понимаю, что sshиспользует shи нет bash.

В Bash я делаю:

cp -r srcdir/!(subdir) dstdir

и работает нормально. Однако, когда я запускаю скрипт через, sshя получаю сообщение об ошибке

sh: 1: Syntax error: "(" unexpected

потому что он использует sh.

Я проверил shсправочную страницу, но нет возможности исключить файлы.

Это мое предположение об sshиспользовании shправильно? Любое альтернативное предложение?

РЕДАКТИРОВАТЬ 1: В случае, если это полезно, выдается sudo cat /etc/shellsследующее:

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

РЕДАКТИРОВАТЬ 2: ОК. Так что Bash это доступно, и это, кажется, не проблема. Я убедился, что ssh на самом деле использует bash. Эта проблема, по-видимому, связана с удалением скобок или восклицательного знака. Я попытался запустить команду из оболочки (MacOS), и это фактическая команда:

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'

Таким образом, я получаю другую ошибку

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

РЕДАКТИРОВАТЬ 3: На основе комментариев я изменил мою команду добавленияextglob

Если я использую

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'

Я получаю следующую ошибку:

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

Если я не уйду в скобки, я получу

bash: -c: line 0: syntax error near unexpected token `('
Rojj
источник
3
ssh(хорошо sshd) использует оболочку входа удаленного пользователя. Может быть что угодно.
Стефан Шазелас
Unix не имеет папок, только каталоги. :)
tchrist
1
В подобных ситуациях мне часто нравится просто разрабатывать сценарий на удаленном хосте, а затем либо 1) оставить его там, ввести ssh (программно, если это необходимо) и выполнить его, либо 2) если он меняется каждый раз, просмотреть его, выполнить это через ssh, а затем удалите его. Может быть, это дополнительный шаг, но вы не в конечном итоге избежите ночных кошмаров и глобусов, расширяющихся локально, а не удаленно и все такое. В противном случае я бы всегда использовал формат heredoc, как @ StéphaneChazelas использует ниже.
Джош Рамбут

Ответы:

10

SSH запускает вашу оболочку входа в систему в удаленной системе, что бы это ни было. Но !(foo)требует shopt -s extglob, который вы, возможно, не установили на пульте.

Попробуйте это, чтобы увидеть, если SSH запускает Bash на удаленной стороне:

ssh me@somehost 'echo "$BASH_VERSION"'

Если это что-то печатает, но ваши сценарии запуска не установлены extglob, вы можете сделать это вручную с помощью команды, переданной ssh:

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

extglob влияет на синтаксический анализ командной строки и вступает в силу только после новой строки, поэтому мы должны поместить туда буквальную новую строку, точки с запятой недостаточно.

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

Также не то, что если вы избежите скобок с обратной косой чертой, они теряют свои особые свойства, как и любые другие символы глобуса. Это не то, что вы хотите сделать в этом случае.

$ touch foo bar; shopt -s extglob; set +o histexpand
$ echo *
bar foo
$ echo !(foo)
bar
$ echo \*
*
$ echo !\(foo\)
!(foo)
ilkkachu
источник
10

Я не знаю, почему вы думаете, что rsync будет медленным. Скорость копирования в основном определяется скоростью диска. Rsync имеет много опций для указания того, что вы хотите включить или исключить, поэтому он дает вам гораздо лучший контроль, чем глобализация оболочки.

Как говорится в руководстве по bash, !(patter)в bash распознается, только если extglobустановлено. В вашем примере вы не установили extglob. Кроме того, bashзапущен как shесть bash, но отключит некоторые расширения для совместимости.

Сервер SSH запустит оболочку входа пользователя, как указано в /etc/passwd. Вы можете либо изменить оболочку, либо использовать ее для запуска другой оболочки, которая лучше соответствует вашим потребностям.

RalfFriedl
источник
Я проверял с time. time cp -r mesh/!(constant) N-> Реальные 1.04 и time rsync -a mesh/ N --exclude=constant-> Реальные 1.8s
Rojj
7
@ Rojj это сравнение яблок с апельсинами. Во-первых, вы используете -a для rsync, но не для cp. Это включает в себя сохранение разрешений и других атрибутов, так что вы на самом деле не делаете то же самое.
Wildcard
6

Сначала несколько заметок:

  • сервер ssh не начинает shинтерпретировать командную строку, отправляемую клиентом, он запускает оболочку входа пользователя на удаленный хост, как that-shell -c <the-string-provided-by-the-client>. Оболочка входа удаленного пользователя может быть любой. Имейте в виду , что некоторые оболочки нравится tcsh, fishили rcимеют очень разный синтаксис от такового sh.
  • на самом деле это командная строка, точнее строка (которая может содержать символы новой строки, поэтому несколько строк). Даже если вы ssh host cmd arg1 'arg 2'где cmd, arg1и arg 2есть три аргумента передаются ssh, sshобъединяющее эти аргументы с пробелами и фактически отправляет cmd arg1 arg 2строку sshdи удаленной оболочки разделит это в cmd, arg1, argи 2.
  • !(subdir)является глобальным оператором ( kshглобальный оператор также поддерживается zsh -o kshglobи bash -O extglob). Как и все глобусы, он исключает скрытые файлы, поэтому будьте осторожны, могут быть и другие файлы, которые он исключает.

Здесь, чтобы избежать проблем с поиском правильного синтаксиса для удаленной оболочки, вы можете указать другой оболочке запустить нужную оболочку и передать ей код через stdin (один из вариантов, перечисленных в разделе Как выполнить произвольный простой команда через ssh, не зная логин оболочки удаленного пользователя? )

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

bash -O extglob -O dotglobэто командная строка, понимается то же самое со всеми основными оболочками, в том числе Борн, как те, CSH, RC, рыбы ... Выше будет работать до тех пор , как bashустановлен и находится в пользователя $PATH( по умолчанию $PATH, возможно , изменен пользователем х вход в оболочку, как с ~/.zshenvдля zsh, ~/.cshrcдля csh, ~/.bashrcдля bash).

POSIXly (хотя на практике вы можете обнаружить, что больше систем имеют bashкоманду, чем paxкоманду), вы можете сделать:

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

-sприменяет замены к передаваемым путям. Когда эта замена расширяется до нуля, файл исключается. Проблема в том, что замены также применяются к цели символических ссылок. Вот почему мы используем .//.выше, чтобы уменьшить вероятность воздействия на символическую ссылку.

Стефан Шазелас
источник
4

Я не думаю, что sshограничивается использованием sh. Скорее, это зависит от того, что установлено в целевой системе, как настроен пользователь и какие оболочки разрешены /etc/shells.

Вы рассматривали chshкоманду?

Рудик
источник
4

Если вы хотите сделать это быстро, вы можете посмотреть rsyncс другим алгоритмом шифрования. Это дает вам возможность легко исключать и т. Д., Не жертвуя скоростью.

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

вместе с добавлением arcfourшифрования в строку, начинающуюся с Ciphersin /etc/ssh/ssh_config, если она еще не включена, дает приемлемую скорость.

ВНИМАНИЕ: arcfourшифрование небезопасно . НЕ запускайте это по незащищенным каналам. Если вы обеспокоены тем, как получить доступ к серверу из ненадежных каналов с помощью arcfourшифрования, изменить etc/ssh/ssh_configс принимающей конкретной частью для вашего хоста источника - Создать Hostраздел в вашем ssh_config для вашего хоста источника, вы можете использовать Ciphers arcfourтам зеркало выше -cпереключателя, который ограничивает arcfourшифрование только этим хостом.

За подробностями обращайтесь к ssh_configсправочным страницам.

Однако, если ваши процессоры поддерживают набор инструкций AES-NI, попробуйте переключиться на aes128-gcm@openssh.com (да, это имя шифра, включая @ stuff), который будет использовать невероятно быстрый (с AES-NI) AES128 -GCM.

Таким образом, с CPU с поддержкой AES-NI, изменение "ssh -T -c arcfour -o Compression=no -x"в "ssh -T -c aes128-gcm@openssh.com -o Compression=no -x"течение более безопасных результатов.

объяснение

Rsync

  • (Не используйте -z, это намного медленнее)
  • a: режим архива - рекурсивный, сохраняет владельца, сохраняет разрешения, сохраняет время модификации, сохраняет группу, копирует символические ссылки как символические ссылки, сохраняет файлы устройств.
  • H: сохраняет жесткие ссылки
  • A: сохраняет ACL
  • X: сохраняет расширенные атрибуты
  • x: не пересекайте границы файловой системы
  • v: увеличить многословие
  • --numeric-ds: не отображать значения uid / gid по имени пользователя / группы
  • если вам нужно синхронизировать, добавьте --delete: удалить посторонние файлы из директорий dest (дифференциальная очистка во время синхронизации)
  • --progress: показать прогресс во время передачи

SSH

  • T: отключить псевдо-tty, чтобы уменьшить загрузку процессора в месте назначения.
  • c arcfour: используйте самое слабое, но самое быстрое шифрование SSH. Необходимо указать "Ciphers arcfour" в sshd_config по назначению.
  • o Compression=no: Отключить сжатие SSH.
  • x: отключить переадресацию X, если она включена по умолчанию.

Говорят в sshопциях - если вы просто используете rsync -avи -e ssh -T -c arcfour -o Compression=no -x"часть, вы также можете получить эти скорости.


Сравнение:

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

Источники :

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

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

emk2203
источник
3
Похоже, они работают cp -rв удаленной системе, поэтому шифрование, используемое соединением SSH, на самом деле не имеет значения. В любом случае arcfourэто считается довольно испорченным, и OpenSSH по умолчанию отключает его вместе с другими на сервере, начиная с версии 6.7 (2014-10-06) . В любом случае, ssh -o Ciphers='aes128-ctr'дает мне около 90 МБ / с, что должно быть достаточно быстрым для канала 1 Гбит / с.
ilkkachu
Да, arcfour не работает, но для этого случая это не SECURE-оболочка, а более «удобная» оболочка без акцента на шифрование. Я бы не стал использовать это из-за небезопасных соединений, это правильно. Если «aes128-ctr» достаточно быстр, его можно и нужно использовать вместо этого.
emk2203
Смотрите также мой расширенный ответ для использования с процессорами, которые поддерживают AES-NI.
emk2203
2

Согласно моим расчетам, самая быстрая полная копия всегда использует 'tar' (здесь предполагается GNU tarили совместимый).

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

И tarимеет множество опций для управления атрибутами, разрешениями и выбором / исключением файлов. Например, приведенная выше команда исключает подпапку верхнего уровня с именем .thumbcache при копировании.

Лам Дас
источник
Обратите внимание , что --exclude=.thumbcacheисключает все эти .thumbcacheфайлы, а не только один на верхнем уровне. С GNU tar(не bsdtar), вы можете использовать --exclude=./.thumbcacheтолько для исключения .thumbcacheфайла верхнего уровня .
Стефан Шазелас